rigetti / pyquil

A Python library for quantum programming using Quil.
http://docs.rigetti.com
Apache License 2.0
1.4k stars 341 forks source link

Add support for QVM's shared memory mode #767

Open stylewarning opened 5 years ago

stylewarning commented 5 years ago

Shared memory mode allows lots of great benefits for high-performance users of the QVM.

  1. It allows the wavefunction to be shared across several processes in parallel.

  2. It allows incremental computation of the wavefunction with successive calls to .run and friends.

  3. It gives NumPy access to the wavefunction.

  4. It allows manual state preparation/initialization.

Shared memory mode is and has been supported by the QVM (--shared) for quite some time, but it's not available in pyQuil since we've only recently released the SDK. The proposal is to add this to pyQuil, probably as a part of wavefunction simulator, but maybe elsewhere.

The following script is a PoC, but is outdated against current pyQuil and is Python 2. It prepares a 4q wavefunction in the W-state, and then inverts the bitstrings with X gates.

#!/usr/bin/env python

### shared_qvm.py
###
### Author: Robert Smith
###
### Copyright (c) 2017-2019 Rigetti Computing

### This file shows a minimal example of how to use the --shared
### option with QVM from Python.
from __future__ import print_function
import posix_ipc as pos
import mmap
import ctypes
import numpy as np

import socket
import json
import sys

from pyquil.api import QVMConnection
from pyquil.quil import Program
from pyquil.gates import X

def query_length_offset(name):
    s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
    s.connect('/tmp/' + name)
    s.sendall("?")
    message, peer = s.recvfrom(4096)
    length, offset = message.split(',')
    return int(length), int(offset)

def retrieve_wavefunction(name):
    length, offset = query_length_offset(name)
    shm = pos.SharedMemory(name)
    m = mmap.mmap(shm.fd, shm.size)
    # get the pointer to what appear to be an array of bytes
    ptr = ctypes.POINTER(ctypes.c_ubyte)(ctypes.c_void_p.from_buffer(m, offset))
    # cast to array of complex double floats
    ptr = ctypes.cast(ptr, np.ctypeslib.ndpointer(shape=(length,), dtype=np.complex128))
    return np.ctypeslib.as_array(ptr)

# Example use of this interface.
if __name__ == '__main__':
    if len(sys.argv) != 2:
        print('Syntax: shared_qvm.py <name>')
        sys.exit(1)
    name = sys.argv[1]
    cxn = QVMConnection(sync_endpoint='http://127.0.0.1:5000')
    wf = retrieve_wavefunction(name)

    print("Initial wavefunction:")
    print(wf)
    print("Initializing to W state.")
    wf[0b0000] = 0j
    wf[0b0001] = (1+0j)/np.sqrt(4)
    wf[0b0010] = (1+0j)/np.sqrt(4)
    wf[0b0100] = (1+0j)/np.sqrt(4)
    wf[0b1000] = (1+0j)/np.sqrt(4)
    print(wf)
    print("Evolving with X3X2X1X0 via QVM. Quil program is:")
    p = Program().inst([X(q) for q in range(4)])
    print(p)
    cxn.run(p, [0])
    print("Printing evolved state.")
    for b in range(len(wf)):
        if not np.isclose(wf[b], 0j):
            print("{0:04b} => {1}".format(b, wf[b]))
34ndju commented 5 years ago

qvm tests are skipped locally. How can I test an implementation of shared memory?

notmgsk commented 5 years ago

qvm tests are skipped locally. How can I test an implementation of shared memory?

Do you mean the shared memory tests are skipped locally? If yes, they are skipped on non-unix operating systems (i.e. Windows): shared memory is not implemented on those systems. So if you want to use shared memory, you will need to use some unix-based OS.

34ndju commented 5 years ago

I'm using unix (macOS). I guess a better question is: How can I test the functionality of my implementation for this?

stylewarning commented 5 years ago

@34ndju You must start the QVM in shared memory mode:

qvm -S --shared shared-mem001 --qubits 4

for instance.

Edit: added a name to the --shared option.

bpcarlos commented 5 years ago

@34ndju You must start the QVM in shared memory mode:

qvm -S --shared --qubits 4

for instance.

When I try to start the QVM with that sentence I obtain the following error:

! ! ! Condition raised: The value
                          T
                        is not of type
                          SEQUENCE
34ndju commented 5 years ago

You have to specify a string for the shared memory name argument. Look at qvm -h

stylewarning commented 5 years ago

@34ndju You must start the QVM in shared memory mode:

qvm -S --shared --qubits 4

for instance.

When I try to start the QVM with that sentence I obtain the following error:

! ! ! Condition raised: The value
                          T
                        is not of type
                          SEQUENCE

Sorry, my bad. As @34ndju said, a string needs to be specified. I edited my comment accordingly.

bpcarlos commented 5 years ago

You have to specify a string for the shared memory name argument. Look at qvm -h

@34ndju You must start the QVM in shared memory mode:

qvm -S --shared --qubits 4

for instance.

When I try to start the QVM with that sentence I obtain the following error:

! ! ! Condition raised: The value
                          T
                        is not of type
                          SEQUENCE

Sorry, my bad. As @34ndju said, a string needs to be specified. I edited my comment accordingly.

Thank you guys. I am trying to make it work, I am now obtaining the following error when I execute the program:

python shared_qvm.py shared-mem001
Traceback (most recent call last):
  File "shared_qvm.py", line 48, in <module>
    wf = retrieve_wavefunction(name)
  File "shared_qvm.py", line 31, in retrieve_wavefunction
    length, offset = query_length_offset(name)
  File "shared_qvm.py", line 25, in query_length_offset
    s.sendall("?")
TypeError: a bytes-like object is required, not 'str'

And in the QVM terminal I obtain the following:

Fatal SOCKET-ERROR: 
  Socket error in "sendto": 32 (Broken pipe)
34ndju commented 5 years ago

Python3 sockets require you to encode prior to sendall() https://stackoverflow.com/questions/33003498/typeerror-a-bytes-like-object-is-required-not-str, and the error in the QVM terminal is likely because your crashing in the Python program is causing a SIGPIPE. Try to encode.