GithubHelp home page GithubHelp logo

quil-lang / qvm Goto Github PK

View Code? Open in Web Editor NEW
410.0 25.0 57.0 1.11 MB

The high-performance and featureful Quil simulator.

License: Other

Makefile 0.92% Common Lisp 98.30% Dockerfile 0.07% Shell 0.28% Python 0.27% Emacs Lisp 0.16%
common-lisp simulator forest quantum-computing quil quantum-virtual-machine

qvm's Introduction

qvm: A High-Performance Quantum Virtual Machine

github release docker pulls DOI

This is the official Quil-Lang Quantum Virtual Machine (QVM), a flexible and efficient simulator for Quil.

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.

QVM, the library

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.

Usage

The QVM library is available on Quicklisp, but of course may not have the latest features. It can be loaded simply with:

* (ql:quickload :qvm)

Alternatively, one can download and load it manually. 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".

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 "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 "H 0")
        :repeat 100
        :for (qvm state) := (multiple-value-list (qvm:measure (qvm:run-program 1 program) 0))
        :do (incf (aref results state))
        :finally (return results))
#(54 46)

Examples

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>):

(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

QVM, the application

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.

Usage

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 cause heap exhaustion. There are two options to ameliorate this.

The first is to increase the memory available for the QVM, recompile and specify the workspace size (in MB)

$ make QVM_WORKSPACE=4096 qvm
$ make install

The second is to use a different allocator when running the QVM, by using the --default-allocator argument with "foreign". For example, to run a 30 qubit benchmark on a QVM configured for far less memory, one can do:

$ qvm --default-allocator "foreign" --benchmark 30 -c

This is not the default since this memory is not fully managed by the application.

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

By default, the QVM accepts programs from stdin and writes results to stdout. Log messages are written to stderr.

Note: If you're on Windows and using the Command Prompt, the echo command is slightly different to the examples shown below: do not wrap your quil code in quotes. For example, in Command Prompt, you would do echo H 0 | qvm not echo "H 0" | qvm.

$ echo 'H 0' | qvm
******************************
* Welcome to the Rigetti QVM *
******************************
Copyright (c) 2016-2019 Rigetti Computing.

(Configured with 8192 MiB of workspace and 8 workers.)

<134>1 2019-03-07T22:56:55Z workstation.local qvm 21177 - - Selected simulation method: pure-state
<134>1 2019-03-07T22:56:55Z workstation.local qvm 21177 - - Reading program.
<134>1 2019-03-07T22:56:55Z workstation.local qvm 21177 - - Allocating memory for QVM of 1 qubits.
<134>1 2019-03-07T22:56:55Z workstation.local qvm 21177 - - Allocation completed in 7 ms.
<134>1 2019-03-07T22:56:55Z workstation.local qvm 21177 - - Loading quantum program.
<134>1 2019-03-07T22:56:55Z workstation.local qvm 21177 - - Executing quantum program.
<134>1 2019-03-07T22:56:55Z workstation.local qvm 21177 - - Execution completed in 4 ms.
<134>1 2019-03-07T22:56:55Z workstation.local qvm 21177 - - Printing classical memory and 1-qubit state.
Classical memory (low -> high indexes):
    No memory.
Amplitudes:
    |0>: 0.7071067811865475,                                    P= 50.0%
    |1>: 0.7071067811865475,                                    P= 50.0%

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.

Testing

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.

Clearing the Cache

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.

Automated Build, Test, and Release with Docker

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. To instead pull a specific version of the QVM, run docker pull rigetti/qvm:VERSION, where VERSION is something like 1.10.0.

Additionally, all branches and commits for the QVM repository have corresponding image tags. For example, the image that contains the HEAD of branch "qvm-fixes" can be pulled with docker pull rigetti/qvm:qvm-fixes (NOTE: some characters are invalid in Docker image tags, and are rewritten according to the description of CI_COMMIT_REF_SLUG). The image built from the commit with first eight characters abcd1234 can be pulled with docker pull rigetti/qvm:abcd1234.

The Dockerfile for qvm builds from two parent Docker images:

  1. rigetti/lisp: Contains SBCL, Quicklisp, and third-party libraries.
  2. rigetti/quilc: Contains the Quil Compiler.

The Dockerfile for qvm intentionally pins the versions of these two images, which means that the version numbers must be actively incremented as necessary. If the build for qvm is failing, this is probably the place to look, because the unit tests are run inside of a freshly-built qvm Docker image as part of the GitLab CI pipeline.

However, because the development workflow for the QVM often involves having a locally cloned copy of quilc master, there are two additional CI jobs that override the version of quilc and instead build off of rigetti/quilc:edge, which corresponds to the HEAD of master. These jobs are optional, meaning that if they fail the overall CI pipeline will not be marked as a failure, but they provide additional useful information to those that develop quilc and the QVM in unison.

Running the QVM with Docker

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

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 -S -p PORT

Port 5000 is exposed using the EXPOSE directive in the rigetti/qvm image, so you can additionally use the -P option to automatically bind this container port to a randomly assigned host port. You can then inspect the mapping using docker port CONTAINER [PORT].

Release Process

  1. Update VERSION.txt and push the commit to master.
  2. Push a git tag vX.Y.Z that contains the same version number as in VERSION.txt.
  3. Verify that the resulting build (triggered by pushing the tag) completes successfully.
  4. Publish a release using the tag as the name.
  5. Close the milestone associated with this release, and migrate incomplete issues to the next one.
  6. Update the qvm version of downstream dependencies (if applicable, see next section).

Downstream Dependencies

Currently, there are a couple different components of the Forest SDK that depend on the QVM:

  1. pyquil
  2. forest-benchmarking

It is the responsibility of the releaser to verify that the latest QVM release does not break the test suites of these downstream dependencies. All of these repositories pull the latest released version of the QVM as part of their CI pipelines.

Feature Flags

The QVM library and application can be built with support for optional features specified by the *features* flag in lisp.

Available Flags

Feature Flag Description
qvm-intrinsics Enable assembly intrinsics in the build, enabling optimized functions based on processor support. Currently supports AVX2 matrix multiplication.

Building QVM with Feature Flags

To build with specific flags enabled, set the QVM_FEATURES variable while building:

$ make QVM_FEATURES='FEATURES' qvm

Note: Cache needs to be cleaned when adding new feature flags to ensure libraries compile with correct flags.

qvm's People

Contributors

appleby avatar ashithecoder avatar braised-babbage avatar colescott avatar ecpeterson avatar erichulburd avatar ftripier avatar jbouwman avatar jlapeyre avatar jmackeyrigetti avatar jmbr avatar karalekas avatar karlosz avatar kartik-s avatar macrologist avatar notmgsk avatar rigettizach avatar sophiaponte avatar spin1half avatar stylewarning avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

qvm's Issues

Separate recording from measurement (was: Make classical memory bit optional in MEASURE)

The functions check whether it is nil, so it should just default to nil

(defmethod measure ((qvm pure-state-qvm) q c)
  (check-type c (or null quil:memory-ref))
  (let* ((r (random 1.0d0))
         (excited-probability (qubit-probability qvm q))
         (cbit (if (<= r excited-probability)
                   1
                   0)))
    ;; Force the non-deterministic measurement.
    (force-measurement cbit q qvm excited-probability)

    ;; Store the classical bit if necessary.
    (unless (null c)
      (setf (dereference-mref qvm c) cbit))

    ;; Return the qvm.
    (values qvm cbit)))

DQVM: mpi sync overload

It's possible we have superfluous syncs. There are the right number between master and worker nodes. However, it's still worth digging deeper. I think it may be possible to remove at least one pair of syncs. Also: there is a sync in reorganize-amplitudes, (and execute-instruction, calls reorganize-amplitudes). It would be better to keep all the syncs in the main loop for both worker and master.

Provide a persistent QVM API

You can start the QVM with a persistent wavefunction using the shared memory command line arguments, but it would be nicer if this could happen on a request-by-request basis.

Allow allocator to be chosen for wavefunction

Right now the Lisp allocator is used for the wavefunction, and there's special case logic for shared memory. But it would be nice if a custom allocator could be provided. That would have the benefit of keeping the heap size small if, for example, a C-allocated vector could be used.

QVM and Quilc don't work behind network proxies

Hi folks,

We're trying to get Forest working on a local machine, and we've run into a problem. Starting up either application in server mode would always return this:

C:\Program Files\Rigetti Computing\Forest SDK for Windows>qvm -S
! ! ! Condition raised: Condition USOCKET:TIMEOUT-ERROR was signalled.
<131>1 2019-05-09T20:47:07Z (hostname) qvm - - - Error encountered, quitting.

Both Linux and Windows installs result in the same behavior. I think I know what's going on, but I'm not familiar with Lisp so my diagnosis could be totally wrong here. Take it with a grain of salt.

After doing a little digging, I found the problem is caused by the latest-sdk-version call in qvm-app-version.lisp. The function uses drakma:http-request, which requires an explicit proxy setting. Since the proxy isn't set, the request times out. The timeout-error condition isn't caught by latest-sdk-version, only ns-host-not-found-error is, so this crashes the program.

We didn't find anything regarding proxy support in the Forest documentation, so we're assuming this is an open issue. At some point, we'd like for proxy support to be added so both tools can check for updates as intended. The lack of proxy support isn't really a blocker for us, though - the problem is how latest-sdk-version handles error conditions. It's breaking the entire program if the update check times out. In our opinion, it should probably just print a warning message if it can't contact the Rigetti server and let QVM and Quilc execute normally.

We're working around this by redirecting traffic aimed at downloads.rigetti.com to our local machine, which is running a webserver that just returns the JSON string that the actual server does, but this is obviously not ideal.

Implement gate fusion

A few years ago, @vontell implemented gate fusion in quilc. Unfortunately, the code never finally landed in master, though the code is preserved.

The goal would be to learn from his approach to gate fusion, and implement it either in quilc or the qvm.

Note that you may need to delete system-index.txt after a failed build

I made some errors when trying to build qvm. After fixing the errors, the build still failed. It looks like deleting system-index.txt in the top-level directory (and also the same filename in both ~/ and in ~/quicklist/local-projects/) solved the error. It would be helpful to include this info in the build instructions.

In shared memory mode, should the QVM still rewire qubits?

For example, when I send the program H 1, the QVM rewrites 1 -> 0 as is expected behavior for using the least number of qubits possible, but for shared memory mode I actually want to apply a Hadamard gate to the qubit indexed 1, because my wavefunction persists from run to run. One can work around this by just applying the identity gate to all qubits at the beginning of the program, but maybe there is a better solution.

Convert `qubits-used` to use the resource abstraction

The compiler routines all use CL-QUIL's resource abstraction, but the QVM uses a routine called qubits-used which separately implements (the qubit portion of) resource utilization tracking. Consider rewriting qubits-used to use the new resource tracking mechanisms, so that this information only has to get updated in one place.

Move linear-algebra.lisp to MAGICL

Not sure how much overlap there is. linear-algebra.lisp defines things like make-matrix, matrix-multiply, and kronecker-multiply that are also available in MAGICL.

Different wavefunction results for empty program and identity program

When using the wavefunction feature of the QVM (from pyQuil), sending the empty program returns a wavefunction array of length 1 (array([1.+0.j])), but sending the program I 0 returns a wavefunction array of length 2 (array([1.+0.j, 0.+0.j])). While I can certainly see the merit of these two returning different things, I'm not sure I would have expected the empty program to behave as such. Thoughts?

bad error message for `echo foo.quil | qvm`

An error in the wild, someone echoing instead of cating, leads to the following:

$ echo foo.quil | qvm
******************************
* Welcome to the Rigetti QVM *
******************************
Copyright (c) 2016-2019 Rigetti Computing.

(Configured with 8192 MiB of workspace and 8 workers.)

! ! ! Condition raised: Couldn't find match at position 3 within the lexer CL-QUIL::LINE-LEXER.

This is of course sensible in its behavior, but the error message is awful and should be more helpful.

qvm-app is a sloppy mess

qvm-app is an organically grown sloppy mess that's difficult to maintain, extend, etc. It wasn't on purpose, but it can be majorly improved.

A good start would be to improve options handling to not pass information through the plethora of globals.

Eliminate buildapp dependency for the qvm

buildapp is super convenient, but it's an inconvenient step in the already inconvenient setup instructions. ASDF offers some portable ways to build, but we could also just have an SBCL-specific build script. (CC @rigettizach)

Logging is not thread safe

This may go into the court of CL-SYSLOG, but calling format-log from multiple threads causes a segfault. Locking it makes it work.

Implement histogramming

Right now, MULTISHOT or MULTISHOT-MEASURE gives bitstrings back. Often it's only necessary to look at a bunch of (uncorrelated) statistics. The QVM maybe should give a way of just giving histograms of |0>/|1> measurements back.

Now, of course this can be written in Quil directly with arithmetic instructions, but understandably, not all hardware easily supports this. If we implemented this as a special API case, we could restrict it to work on single BITs of memory.

Strange behavior when using the random seed for the QVM

I have been working with @kylegulshen on a PR to forest-benchmarking that changes some unit tests which use the QVM. Strangely, there were some tests that failed when the full test suite was run, but not when run alone. There certainly could be other issues at play here, but on a whim I decided to change the QVM's random seed for one of the failing tests from 1 to 2 and suddenly things began working, which seemed alarming to me. I sense that there could be something deeper going on, so I just wanted to get this issue in writing and maybe spur some investigation.

Shared memory error when profiling is enabled

Fixing the profiler (see quilc) results in an error:

# snip

TEST-DENSITY-QVM-NOISY-MEASURE-ALL                                      [ OK ]
[Test output: aaaaaaaaa]
  TEST-QVM-GARBAGE-COLLECTION                                             [ OK ]
[Test output: awdawdawdawdawdawdawdawdawdawdawdawdawdawdawdawd]
  TEST-POSIX-SHARED-MEMORY-ALLOCATION/DEALLOCATION                        [ OK ]
[Test output: awdawdawdawdawdawdawdawdawdawdawdawdawdawdawdawd]
  TEST-SHARED-ARRAY-ALLOCATION/DEALLOCATION                               [ OK ]
[Test output: aaaaaaaWhile evaluating the form starting at line 36, column 0
  of #P"/Users/mark.skilbeck/hackery/qvm/coverage-report/coverage-report.lisp":

debugger invoked on a SIMPLE-ERROR in thread
#<THREAD "main thread" RUNNING {10005C05B3}>:
  Error in shm_open. Got return code -1: File exists

Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.

restarts (invokable by number or by possibly-abbreviated name):
  0: [CONTINUE                             ] Skip the rest of the test
                                             TEST-SHARED-QVM-GARBAGE-COLLECTION
                                             and continue by returning (values)
  1: [RETEST                               ] Rerun the test
                                             TEST-SHARED-QVM-GARBAGE-COLLECTION
  2:                                         Skip the rest of the test
                                             FIASCO-SUITES::QVM-TESTS and
                                             continue by returning (values)
  3:                                         Rerun the test
                                             FIASCO-SUITES::QVM-TESTS
  4: [CONTINUE-WITHOUT-DEBUGGING           ] Turn off debugging for this test
                                             session and invoke the first
                                             CONTINUE restart
  5: [CONTINUE-WITHOUT-DEBUGGING-ERRORS    ] Do not stop at unexpected errors
                                             for the rest of this test session
                                             and continue by invoking the first
                                             CONTINUE restart
  6: [CONTINUE-WITHOUT-DEBUGGING-ASSERTIONS] Do not stop at failed assertions
                                             for the rest of this test session
                                             and continue by invoking the first
                                             CONTINUE restart
  7: [ABORT-TESTING                        ] Abort the entire test session
  8: [RETRY                                ] Retry
                                             #<TEST-OP > on #<SYSTEM "qvm-tests">.
  9: [ACCEPT                               ] Continue, treating
                                             #<TEST-OP > on #<SYSTEM "qvm-tests">
                                             as having been successful.
 10:                                         Retry ASDF operation.
 11: [CLEAR-CONFIGURATION-AND-RETRY        ] Retry ASDF operation after
                                             resetting the configuration.
 12:                                         Retry ASDF operation.
 13:                                         Retry ASDF operation after
                                             resetting the configuration.
 14: [RETRY                                ] Retry EVAL of current toplevel form.
 15:                                         Ignore error and continue loading file "/Users/mark.skilbeck/hackery/qvm/coverage-report/coverage-report.lisp".
 16: [ABORT                                ] Abort loading file "/Users/mark.skilbeck/hackery/qvm/coverage-report/coverage-report.lisp".
 17:                                         Ignore runtime option --load "coverage-report.lisp".
 18:                                         Skip rest of --eval and --load options.
 19:                                         Skip to toplevel READ/EVAL/PRINT loop.
 20: [EXIT                                 ] Exit SBCL (calling #'EXIT, killing the process).

(QVM::MAKE-POSIX-SHARED-MEMORY "TEST_C__7" 1073741840)
   source: (ERROR "Error in shm_open. Got return code ~D: ~A" FD
                  (%STRERROR %ERRNO))
0]

It only happens when profiling is enabled.

Analyze and document numerical stability

Numerical stability has been "casually" thought about, but not very many intentional design decisions exist on its behalf. Numerical stability should be thought about, and there should be some documentation written about the findings.

Investigate (and implement?) positive-Wigner efficient simulation

Quantum contextuality is known to be a key ingredient in producing quantum speedup—and, hence, in stymieing efficient classical simulation of quantum systems. As a sort of converse, Raussendorf et al. (https://arxiv.org/pdf/1905.05374.pdf) have a paper where they propose a scheme with the following traits:

  1. Their method for simulation is 'efficient', presumably meaning that resource consumption scales polynomially with the number of qubits requested.
  2. Their method for simulation subsumes the Gottesman stabilizer formalism.
  3. The condition on Wigner functions is tightly coupled (though I am not clear on precisely how tightly) with non-contextuality, which is a gesture at the genericity of this method.

I haven't read this paper myself, but it seems like it could be reasonable fodder for a new QVM simulation mode. Someone ought to investigate.

Remove *program* from DQVM

In main, we have a global var *program*. We should remove this.
(We should be able to just have a program local var in process-options.)

implement readout symmetrization option for MEASURE

@marcusps suggests that readout symmetrization is a useful way to improve error rates in readout by averaging over measurement of 0 and 1 states. The general procedure, as I understand it, is this:

Given an instruction like

MEASURE q c

uniformly randomly either do nothing, or transform it to

X q
MEASURE q c
NOT c

This will, over many shots, symmetrize the behavior of MEASURE, giving it asymptotically 50% chance of reading out 0 or 1.

It would not be wise to actually transform the Quil program, and this sort of thing ought to happen during compilation to actual quantum machine code. But for the purpose of simulating error, we can install this behavior into a transition method, probably on the noisy-qvm class where it's actually useful.

DQVM: improve resolving quil input

In DQVM src/main.lisp, there is a function resolve-safely. Similar functionality may already exist, in qvm or quilc. We should try to replace the validation that occurs within that function with an existing function, if there is one.

make test-app fails: Package QUILC does not exist

I get the following error when attempting to run make cleanall && make test-app.

$ make QUICKLISP_HOME=~/opt/rigetti-quicklisp test-app
sbcl --dynamic-space-size 2048 --noinform --non-interactive --no-userinit --no-sysinit --load /home/ma/opt/rigetti-quicklisp/setup.lisp --eval '(push (truename ".") asdf:*central-registry*)' --eval '(push :hunchentoot-no-ssl *features*)' --eval '(push :drakma-no-ssl *features*)' --eval "(push (truename \"../\") ql:*local-project-directories*)" \
         --eval '(ql:quickload :qvm-app-tests)' \
         --eval '(asdf:test-system :qvm-app)'
To load "qvm-app-tests":
  Load 1 ASDF system:
    qvm-app-tests
; Loading "qvm-app-tests"

...snip...

[package qvm-app-tests].....;
; caught ERROR:
;   READ error during COMPILE-FILE:
;
;     Package QUILC does not exist.
;
;       Line: 169, Column: 35, File-Position: 7260
;
;       Stream: #<SB-INT:FORM-TRACKING-STREAM for "file /home/ma/src/repos/rigetti/qvm/app/tests/suite.lisp" {1013E310A3}>
Unhandled UIOP/LISP-BUILD:COMPILE-FILE-ERROR in thread #<SB-THREAD:THREAD "main thread" RUNNING
                                                          {10005205B3}>:
  COMPILE-FILE-ERROR while compiling #<CL-SOURCE-FILE "qvm-app-tests" "suite">

Backtrace for: #<SB-THREAD:THREAD "main thread" RUNNING {10005205B3}>
0: (SB-DEBUG::DEBUGGER-DISABLED-HOOK #<UIOP/LISP-BUILD:COMPILE-FILE-ERROR {1010E14563}> #<unused argument> :QUIT T)
1: (SB-DEBUG::RUN-HOOK *INVOKE-DEBUGGER-HOOK* #<UIOP/LISP-BUILD:COMPILE-FILE-ERROR {1010E14563}>)
2: (INVOKE-DEBUGGER #<UIOP/LISP-BUILD:COMPILE-FILE-ERROR {1010E14563}>)
3: (ERROR UIOP/LISP-BUILD:COMPILE-FILE-ERROR :CONTEXT-FORMAT "~/asdf-action::format-action/" :CONTEXT-ARGUMENTS ((#<ASDF/LISP-ACTION:COMPILE-OP > . #<ASDF/LISP-ACTION:CL-SOURCE-FILE "qvm-app-tests" "suite">)))

...snip...

This appears to be due to the following test, which was recently added to app/tests/suite.lisp:

(deftest test-server-startup-behaviour ()
  ;; Test that providing -p without -S does *not* start the server.
  (is (typep (with-input-from-string (*standard-input* "H 0")
               (quilc::%entry-point (list "quilc" "-p" "1000")))
             'hash-table))
  ;; TODO One day, some more checks that quilc behaves.
  )

Perhaps test-server-startup-behaviour is meant to test the option processing in qvm-app, not quilc? Otherwise, I guess quilc needs to be added as a dependency in qvm-app-tests.asd.

wavefunction-qubits is sometimes not used

DQVM style fixes

DQVM src/common.lisp

docstring for +worker-count+
;;; The number of worker nodes. -> ;;; The number of worker nodes, which is the total number of nodes minus the master node.

with-total-readability
Print something with as many readability settings turned on. ->  Print something with many readability settings turned on. (or, as many... as possible)

cluster struct definition
*CLUSTER* should be **CLUSTER**

deserialize-cluster
Can we use clusterp rather than (typep c 'cluster)?

DQVM src/worker.lisp

first line: (declaim (optimize (speed 0) safety debug (compilation-speed 0))) probably warrants a comment

number-of-blocks
doctring should describe that these are the number of blocks across all workers, not per worker

iterate-worker-addresses
could use some good documentation, and we should see what else we can do to make it more readable

%main-worker
docstring is missing a period Main entry point to the worker This is only to be called by DQVM:%MAIN. -> Main entry point to the worker. This is only to be called by DQVM:%MAIN.
First comment ;; Wait for master to sync seems like it may be misplaced; I think we can delete.

Determine parallelization limit per machine

The variable *qubits-required-for-parallelization* is statically set to 19, which means that as soon as 19 qubits is reached in a computation, the computations will be parallelized.

This isn't ideal for all machines. Sometimes parallelization provides gains with values lower or higher than 19. The goal of this issue would be to search for that crossing point and optimize accordingly.

Problems that must be solved in order to solve this issue:

  • How should the parallelization limit be calculated? (This is slightly non-trivial because many different things are parallelized in different contexts.)
  • How can one invoke this calculation?
  • Should the parallelization limit be stored on disk? Should it be provided as a command-line argument?

support quil:measure-discard in density-qvm

Currently measurement on the density-qvm forces a particular measurement by way of a coin flip. This is correct behavior for the measurement instruction

MEASURE q c

However, it's not correct behavior for a bare measure-and-discard. This has the syntax

MEASURE q

and class quil:measure-discard. In this case, we should produce a mixed state on |0> and |1>. This can be accomplished by defining a transition method on density-qvm and quil:measure-discard.

Parallelization limit causes unintuitive timing benchmarks (was: Multi-thread support is unclear)

I am running the SDK QVM version 1.3.2 and ran into a very puzzling issue;

As far as I understood the QVM supports multiple workers/living on different threads. This is also what I find with qvm --benchmark, which by default runs a 26 qubit experiment. I'm running on a 12-core AMD 1920X which supports 24 threads, and during the benchmark I observe all CPU threads are active.

However, I am observing a strange deviation in run-time, in addition to CPU usage jumping from 100% to ~1500%, when I increase the qubit number from 18 to 19.

Minimal working example (I compiled the below via pyquil, and not directly in lisp, but below I show another example in command line QVM. ):

from pyquil.quil import Program
from pyquil.gates import H, CNOT, MEASURE
from pyquil.api import get_qc
import time


def test_multi_thread(N):
    prog = Program()
    ro = prog.declare('ro', memory_type='BIT', memory_size=N)

    prog += H(0)
    for j in range(N-1):
        prog += CNOT(j, j+1)

    for j in range(N):
        prog += MEASURE(j, ro[j])

    prog.wrap_in_numshots_loop(40)
    qc = get_qc(str(N)+'q-qvm')
    binary = qc.compile(prog)

    t = time.time()
    bitstrings = qc.run(binary)
    return time.time()-t


for n in [16, 17, 18, 19, 20, 21, 22]:
    print(str(n)+'-qubit experiment took ' + str(test_multi_thread(n))[:5] + ' seconds')

Then, the output for my particular machine results in:
16-qubit experiment took 5.752 seconds
17-qubit experiment took 12.02 seconds
18-qubit experiment took 26.18 seconds
19-qubit experiment took 8.229 seconds
20-qubit experiment took 14.66 seconds
21-qubit experiment took 29.66 seconds
22-qubit experiment took 53.15 seconds

Clearly, the 19-qubit experiment took shorter time than the 18 and even 17 qubit case. Based on the system monitor showing activity on a single vs multiple threads, therefore a hypothesis is multi-thread is enabled only past 18 qubits?

Also, I tested it by running the benchmark and it gives me this for 18 qubits:

qvm --benchmark 18
******************************
* Welcome to the Rigetti QVM *
******************************
Copyright (c) 2016-2019 Rigetti Computing.

This is a part of the Forest SDK. By using this program
you agree to the End User License Agreement (EULA) supplied
with this program. If you did not receive the EULA, please
contact <[email protected]>.

(Configured with 10240 MiB of workspace and 24 workers.)

<134>1 2019-02-20T21:12:36Z vincentelfving-linux qvm 21685 - - Selected simulation method: pure-state
<134>1 2019-02-20T21:12:36Z vincentelfving-linux qvm 21685 - - Computing baseline serial norm timing...
<134>1 2019-02-20T21:12:36Z vincentelfving-linux qvm 21685 - - Baseline serial norm timing: 0 ms
<134>1 2019-02-20T21:12:36Z vincentelfving-linux qvm 21685 - - Starting "bell" benchmark with 18 qubits...

Evaluation took:
  0.134 seconds of real time
  0.134324 seconds of total run time (0.134324 user, 0.000000 system)
  100.00% CPU

which shows 100.00% CPU for 18 qubits, while if I select a benchmark with 19 qubits:

qvm --benchmark 19
******************************
* Welcome to the Rigetti QVM *
******************************
Copyright (c) 2016-2019 Rigetti Computing.

This is a part of the Forest SDK. By using this program
you agree to the End User License Agreement (EULA) supplied
with this program. If you did not receive the EULA, please
contact <[email protected]>.

(Configured with 10240 MiB of workspace and 24 workers.)

<134>1 2019-02-20T21:12:31Z vincentelfving-linux qvm 21660 - - Selected simulation method: pure-state
<134>1 2019-02-20T21:12:31Z vincentelfving-linux qvm 21660 - - Computing baseline serial norm timing...
<134>1 2019-02-20T21:12:31Z vincentelfving-linux qvm 21660 - - Baseline serial norm timing: 1 ms
<134>1 2019-02-20T21:12:31Z vincentelfving-linux qvm 21660 - - Starting "bell" benchmark with 19 qubits...

Evaluation took:
  0.087 seconds of real time
  1.281765 seconds of total run time (1.079780 user, 0.201985 system)
  1473.56% CPU

it shows 1473.56% CPU... another indicator. Note that I find the same results with the option -w 24 added (which makes sense, it already defaulted to my system max of 24).

Is this behaviour reproduced on your side? If so, is it intentional?

Parallelize MULTISHOT

Right now, MULTISHOT experiments under the parallelization limit only use a single core. We could use this as an opportunity to do multicore computations. The general flow would be:

  1. Is the computation under the parallelization limit? If no, perform single-threaded.
  2. Does the computation exceed the number of shots necessary to parallelize? If no, perform single-threaded.
  3. Parallelize across threads, each modifying thread-local state, then combine state.

This was requested by the Slack community.

qft benchmark doesn't work

$ ./qvm --benchmark --benchmark-type qft
******************************
* Welcome to the Rigetti QVM *
******************************
Copyright (c) 2016-2019 Rigetti Computing.

(Configured with 8192 MiB of workspace and 8 workers.)

<135>1 2019-04-26T17:14:15Z naan.local qvm 85238 - - Selected simulation method: pure-state
! ! ! Condition raised: No restart CONTINUE is active.
<131>1 2019-04-26T17:14:16Z naan.local qvm 85238 - - Error encountered, quitting.

Don't mutate program in LOAD-PROGRAM

When PR #58 lands, LOAD-PROGRAM will mutate the program being loaded because patch-labels is being called. We should do work so that this mutation doens't cause unintended side-effects.

QVM performance cliff at a specific number of shots

It is not super clear which part is to blame (it could just be the serialization/deserialization) but there is a surprising performance hit at a specific number of shots for a simple 1Q program

(base) cryan@cryan-Precision-5510 ~ $ qvm --version
1.5.0 [aacb70c]
(base) cryan@cryan-Precision-5510 ~ $ qvm -S
******************************
* Welcome to the Rigetti QVM *
******************************
Copyright (c) 2016-2019 Rigetti Computing.

This is a part of the Forest SDK. By using this program
you agree to the End User License Agreement (EULA) supplied
with this program. If you did not receive the EULA, please
contact <[email protected]>.

(Configured with 10240 MiB of workspace and 8 workers.)

<134>1 2019-03-26T00:07:34Z cryan-Precision-5510 qvm 4752 - - Selected simulation method: pure-state
<134>1 2019-03-26T00:07:34Z cryan-Precision-5510 qvm 4752 - - Starting server on port 5000.
import pyquil
print(pyquil.__version__)
2.5.2

from pyquil import Program, get_qc0
from pyquil.gates import *

qc = get_qc('1q-qvm')

NUM_SHOTS = 973
prog_a = Program()
ro = prog_a.declare('ro', 'BIT', 1)
prog_a += RX(np.pi/2, 0)
prog_a += MEASURE(0, ro[0])
prog_a.wrap_in_numshots_loop(NUM_SHOTS)
%timeit bitstrings = np.array(qc.run(prog_a))

6.15 ms ± 471 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

NUM_SHOTS = 974
prog_a = Program()
ro = prog_a.declare('ro', 'BIT', 1)
prog_a += RX(np.pi/2, 0)
prog_a += MEASURE(0, ro[0])
prog_a.wrap_in_numshots_loop(NUM_SHOTS)
%timeit bitstrings = np.array(qc.run(prog_a))

59.6 ms ± 1.16 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

The QVM shows that "Finished in" goes from 2-3 ms to 9-10ms so a surprising jump but not largely responsible.

make test fails: The slot CL-QUIL::DIMENSION is unbound in the object #<PERMUTATION-GATE {1005F86273}>

I get the following error when running make cleanall && make test.

I was concerned this might be related to my recent changes in cl-quil.tweedledum, so I ran a make clean in the quilc directory as well.

Unhandled UNBOUND-SLOT in thread #<SB-THREAD:THREAD "main thread" RUNNING
                                    {10005205B3}>:
  The slot CL-QUIL::DIMENSION is unbound in the object
  #<PERMUTATION-GATE {1005F86273}>.

Backtrace for: #<SB-THREAD:THREAD "main thread" RUNNING {10005205B3}>
0: (SB-DEBUG::DEBUGGER-DISABLED-HOOK #<UNBOUND-SLOT DIMENSION {1005F86643}> #<unused argument> :QUIT T)
1: (SB-DEBUG::RUN-HOOK SB-EXT:*INVOKE-DEBUGGER-HOOK* #<UNBOUND-SLOT DIMENSION {1005F86643}>)
2: (INVOKE-DEBUGGER #<UNBOUND-SLOT DIMENSION {1005F86643}>)
3: (ERROR #<UNBOUND-SLOT DIMENSION {1005F86643}>)
4: (SB-KERNEL:WITH-SIMPLE-CONDITION-RESTARTS ERROR NIL UNBOUND-SLOT :NAME CL-QUIL::DIMENSION :INSTANCE #<CL-QUIL:PERMUTATION-GATE {1005F86273}>)
5: ((:METHOD SLOT-UNBOUND (T T T)) #<unused argument> #<CL-QUIL:PERMUTATION-GATE {1005F86273}> CL-QUIL::DIMENSION) [fast-method]
6: ((LAMBDA (SB-KERNEL:INSTANCE) :IN SB-PCL::MAKE-OPTIMIZED-STD-READER-METHOD-FUNCTION) #<CL-QUIL:PERMUTATION-GATE {1005F86273}>)
7: ((:METHOD TRANSITION (PURE-STATE-QVM CL-QUIL:GATE-APPLICATION)) #<PURE-STATE-QVM {1005F20513}> #<CONTROLLED X 0 1>) [fast-method]
8: ((:METHOD RUN (PURE-STATE-QVM)) #<PURE-STATE-QVM {1005F20513}>) [fast-method]
9: ((FLET "EXECUTION-BODY-1" :IN TEST-CONTROLLED-X))
10: ((LABELS TEST-CONTROLLED-X :IN TEST-CONTROLLED-X))
11: ((LABELS FIASCO::RUN-TEST-BODY :IN FIASCO::RUN-TEST-BODY-IN-HANDLERS))
12: (FIASCO::CALL-WITH-TEST-HANDLERS #<CLOSURE (LAMBDA NIL :IN FIASCO::RUN-TEST-BODY-IN-HANDLERS) {1005EFD7AB}>)
13: (FIASCO::PRETTY-RUN-TEST #<test TEST-CONTROLLED-X> #<FUNCTION (LABELS TEST-CONTROLLED-X :IN TEST-CONTROLLED-X) {53F0DEAB}>)
14: ((LABELS #:BODY-SYM0 :IN TEST-CONTROLLED-X))
15: (TEST-CONTROLLED-X)
16: ((LABELS FIASCO-SUITES::QVM-TESTS :IN FIASCO-SUITES::QVM-TESTS))
17: ((LABELS FIASCO::RUN-TEST-BODY :IN FIASCO::RUN-TEST-BODY-IN-HANDLERS))

Don't run all tests in both modes

The test suite is taking a good while to finish. This could be improved by running only specific tests in both intepreted and compiled modes.

UNIXy nature of QVM isn't working

naan:qvm robert$ echo 'H 0' | ./qvm
******************************
* Welcome to the Rigetti QVM *
******************************
Copyright (c) 2016-2019 Rigetti Computing.

(Configured with 8192 MiB of workspace and 8 workers.)

<135>1 2019-04-26T17:12:11Z naan.local qvm 85234 - - Selected simulation method: pure-state
<135>1 2019-04-26T17:12:11Z naan.local qvm 85234 - - Starting server on port 5000.
$ echo 'H 0' | ./qvm -e
******************************
* Welcome to the Rigetti QVM *
******************************
Copyright (c) 2016-2019 Rigetti Computing.

(Configured with 8192 MiB of workspace and 8 workers.)

<135>1 2019-04-26T17:13:19Z naan.local qvm 85236 - - Selected simulation method: pure-state
<132>1 2019-04-26T17:13:19Z naan.local qvm 85236 - - --execute/-e is deprecated. Elide this option for equivalent behavior.
<135>1 2019-04-26T17:13:19Z naan.local qvm 85236 - - Warning: Ignoring execute option: T
<135>1 2019-04-26T17:13:19Z naan.local qvm 85236 - - Starting server on port 5000.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.