Git Product home page Git Product logo

pyquil's Introduction

PyQuil: Quantum programming in Python

binder docs docker pepy pypi slack

PyQuil is a Python library for quantum programming using Quil, the quantum instruction language developed at Rigetti Computing. PyQuil serves three main functions:

PyQuil has a ton of other features, which you can learn more about in the docs. However, you can also keep reading below to get started with running your first quantum program!

Quickstart with interactive tutorial notebooks

Without installing anything, you can quickly get started with quantum programming by exploring our interactive Jupyter notebook tutorials and examples. To run them in a preconfigured execution environment on Binder, click the "launch binder" badge at the top of the README or the link here! To learn more about the tutorials and how you can add your own, visit the rigetti/forest-tutorials repository. If you'd rather set everything up locally, or are interested in contributing to pyQuil, continue onto the next section for instructions on installing pyQuil and the Forest SDK.

Installing pyQuil and the Forest SDK

pypi conda-forge conda-rigetti

PyQuil can be installed using conda, pip, or from source. To install it from PyPI (via pip), do the following:

pip install pyquil

To instead install pyQuil from source, do the following from within the repository after cloning it:

pip install -e .

If you choose to use pip, we highly recommend installing pyQuil within a virtual environment.

PyQuil, along with quilc, the QVM, and other libraries, make up what is called the Forest SDK. To make full use of pyQuil, you will need to additionally have installed quilc and the QVM. For more information, check out the docs!

Running your first quantum program

In just a few lines, we can use pyQuil with the Forest SDK to simulate a Bell state!

from pyquil import get_qc, Program
from pyquil.gates import CNOT, H, MEASURE
 
qvm = get_qc('2q-qvm')
 
p = Program()
p += H(0)
p += CNOT(0, 1)
ro = p.declare('ro', 'BIT', 2)
p += MEASURE(0, ro[0])
p += MEASURE(1, ro[1])
p.wrap_in_numshots_loop(10)

qvm.run(p).get_register_map()['ro'].tolist()

The output of the above program should look something like the following, the statistics of which are consistent with a two-qubit entangled state.

[[0, 0],
 [1, 1],
 [1, 1],
 [1, 1],
 [1, 1],
 [0, 0],
 [0, 0],
 [1, 1],
 [0, 0],
 [0, 0]]

Using the Forest SDK, you can simulate the operation of a real quantum processor (QPU). If you would like to run on the real QPUs in our lab in Berkeley, you can sign up for an account on Quantum Cloud Services (QCS)!

Joining the Forest community

If you'd like to get involved with pyQuil and Forest, joining the Rigetti Forest Slack Workspace is a great place to start! You can do so by clicking the invite link in the previous sentence, or in the badge at the top of this README. The Slack Workspace is a great place to ask general questions, join high-level design discussions, and hear about updates to pyQuil and the Forest SDK.

To go a step further and start contributing to the development of pyQuil, good first steps are reporting a bug, requesting a feature, or picking up one of the issues with the good first issue or help wanted labels. Once you find an issue to work on, make sure to fork this repository and then open a pull request once your changes are ready. For more information on all the ways you can contribute to pyQuil (along with some helpful tips for developers and maintainers) check out our Contributing Guide!

To see what people have contributed in the past, check out the Changelog for a detailed list of all announcements, improvements, changes, and bugfixes. The Releases page for pyQuil contains similar information, but with links to the pull request for each change and its corresponding author. Thanks for contributing to pyQuil! ๐Ÿ™‚

Citing pyQuil, Forest, and Quantum Cloud Services

zenodo

If you use pyQuil, Grove, or other parts of the Forest SDK in your research, please cite the Quil specification using the following BibTeX snippet:

@misc{smith2016practical,
    title={A Practical Quantum Instruction Set Architecture},
    author={Robert S. Smith and Michael J. Curtis and William J. Zeng},
    year={2016},
    eprint={1608.03355},
    archivePrefix={arXiv},
    primaryClass={quant-ph}
}

Additionally, if your research involves taking data on Rigetti quantum processors (QPUs) via the Quantum Cloud Services (QCS) platform, please reference the QCS paper using the following BibTeX snippet:

@article{Karalekas_2020,
    title = {A quantum-classical cloud platform optimized for variational hybrid algorithms},
    author = {Peter J Karalekas and Nikolas A Tezak and Eric C Peterson
              and Colm A Ryan and Marcus P da Silva and Robert S Smith},
    year = 2020,
    month = {apr},
    publisher = {{IOP} Publishing},
    journal = {Quantum Science and Technology},
    volume = {5},
    number = {2},
    pages = {024003},
    doi = {10.1088/2058-9565/ab7559},
    url = {https://doi.org/10.1088%2F2058-9565%2Fab7559},
}

The preprint of the QCS paper is available on arXiv, and the supplementary interactive notebooks and datasets for the paper can be found in the rigetti/qcs-paper repository.

License

PyQuil is licensed under the Apache License 2.0.

pyquil's People

Contributors

ameyer-rigetti avatar ampolloreno avatar appleby avatar bramathon avatar cbosborn avatar dbanty avatar ecpeterson avatar erichulburd avatar gecrooks avatar harleypatton avatar jotterbach avatar jselig-rigetti avatar kalzoo avatar karalekas avatar kylegulshen avatar lcapelluto avatar mac01021 avatar marquessv avatar mhodson-rigetti avatar mpharrigan avatar msohaibalam avatar mstechly avatar ncrubin avatar notmgsk avatar ntezak avatar rht avatar semantic-release-bot avatar stevenheidel avatar vontell avatar willzeng 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  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

pyquil's Issues

pyQuil programs should return the list of allocated qubits

This a useful feature for compilation and analysis that can be built as a method on pyQuil program objects, e.g.

pq = Program(X(0), CNOT(0, 1))
assert pq.get_qubits() == [0, 1]

qq = pq.alloc()
pq.inst(X(qq))
assert pq.get_qubits() == [0, 1, 2] # this synthesizes the allocation

Bit indices reversed from bit_string_probabilities to measured

When running the following code, there are some conflicting results:

def test():
  
  qvm = forest.Connection()
  p = Program()
  
  p.inst(X(0))
  p.inst(X(1))
  p.inst(I(2))
  
  print qvm.bit_string_probabilities(p)
  print qvm.wavefunction(p)[0]
  p.measure(0, 0).measure(1, 1).measure(2, 2)
  
  print p
  return qvm.run(p, range(3))

print test()

I would expect this piece of code to transform my initial | 000 > state into | 110 >. The final result of running and measuring this code does return this result, but qvm.bit_string_probabilities(p) and print qvm.wavefunction(p)[0] do not have what I expect:

{'010': 0.0, '011': 1.0, '001': 0.0, '000': 0.0, '111': 0.0, '110': 0.0, '100': 0.0, '101': 0.0}
[ 0.+0.j  0.+0.j  0.+0.j  1.+0.j  0.+0.j  0.+0.j  0.+0.j  0.+0.j]

The ordering of the bits seems to be off; instead of 110 having an amplitude/probability of 1, 011 has an amplitude/probability of 1. After trying this out on a few other qubit variations, it seems that the results are reversed.

if not then

Increase functionality of control flow conditioned on classical memory position to include JUMP-UNLESS @something [0]. Streamlines many empty JUMP-WHEN blocks making control flow cleaner.

enforcing type of `classical_addresses` in `qvm.wavefunction()` contradicts tutorial

The following is quoted from an email received from Molly Saxelby via our support system:

As I continued through the documentation, I encountered another error with the following example:

wavf, classical_mem = qvm.wavefunction(coin_flip, classical_addresses=range(9))

I got the following error:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Applications/anaconda/lib/python3.6/site-packages/pyquil/api.py", line 356, in wavefunction
    _validate_run_items(classical_addresses)
  File "/Applications/anaconda/lib/python3.6/site-packages/pyquil/api.py", line 149, in _validate_run_items
    raise TypeError("run_items must be a list")
TypeError: run_items must be a list
>>> wavf, classical_mem = qvm.wavefunction(coin_flip, classical_addresses={0,1,2,3,4,5,6,7,8})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Applications/anaconda/lib/python3.6/site-packages/pyquil/api.py", line 356, in wavefunction
    _validate_run_items(classical_addresses)
  File "/Applications/anaconda/lib/python3.6/site-packages/pyquil/api.py", line 149, in _validate_run_items
    raise TypeError("run_items must be a list")
TypeError: run_items must be a list

I fixed the error by changing the range to a list:

wavf, classical_mem = qvm.wavefunction(coin_flip, classical_addresses=[0,1,2,3,4,5,6,7,8, 9])

The tutorial, however suggests using range as above, as it was written with python 2.7 in mind. I suggest we explicitly convert classical_addresses to a list rather than raise an exception.

.pyquil_config not created

Working in MacOS. Even after sudo pip install pyquil twice (uninstalled after first time, of course), I couldn't find any .pyquil_config file in my home directory.
I got a HTTPError: 403 Client Error: Forbidden for url: https://api.rigetti.com/qvm

Finally had to create .pyquil_config manually in my home directory and add that to my bash profile
export PYQUIL_CONFIG="$HOME/.pyquil_config"

Was that necessary? I was under the impression that it would all be taken care automatically with the pip install itself. Is this an error because of my way of installation, or should we modify api.py script so that we can jump over this manual labour?

Plus, I cant find pyquil-config-setup in my setup.py

Wavefunction for >=20 qubits hangs

There seems to be an issue when one attempts to compute the wavefunction on 20 or more qubits. Here's a repro:

import pyquil.quil as pq
import pyquil.forest as forest
from pyquil.gates import *

cxn = forest.Connection()

def hadamard(n):
    p = pq.Program()
    for q in xrange(n):
        p.inst(H(q))
    return p

for i in xrange(20):
    p = hadamard(i+1)
    wf, _ = cxn.wavefunction(p)
    print i+1, "=>", len(wf)

It is known that this is purely a communications issue. 20-qubit computations can be done with non-wavefunction calls. Moreover, the wavefunction does get computed, and it does get sent from the application server, but it doesn't jump through all the hoops to get back to pyQuil.

Error importing forest/api for Meyer-Penny Game

Going through the docs and trying to create the Picard vs Q coin toss (https://pyquil.readthedocs.io/en/latest/examples.html). Up until now, everything has in the previous pages of the docs has been working as described, however now I'm getting an error when trying to import forest.

My .pyquil_config file is setup in the home directory as shown below.
[Rigetti Forest]
url: https://api.rigetti.com/qvm
key: nmRPAVunQl19TtQz9eMd11iiIsArtUDTaEnsSV6u
user_id: 6506ed6b-16b6-424d-8b15-2e5c9e2b70d0

Tried changing the import statement "from pyquil import forest" to "from pyquil.api import api", and then changing "qvm = forest.Connection()" to "qvm = api.SyncConnection()". This also returned an error: "cannot import name api"

Reason for 502 Error?

At the moment I am working on writing Grover's algorithm for an arbitrary number of qubits, and I came across the following problem:

requests.exceptions.HTTPError: 502 Server Error: Bad Gateway for url: https://api.rigetti.com/qvm

This happens any time I try to run it with 8 or more qubits, and I think the problem is that I'm defining some gates very inefficiently. At some point I need to define some 8+1-qubit gate, and I do this by creating a 2^9 x 2^9 matrix. However, the matrix is incredibly simple. It is a diagonal matrix with all 1s on the diagonal, except the last entry is -1. Is there a way of defining your own gates by using sparse arrays/matrices?

This error message should be reproducible by defining any arbitrary 9+-qubit gate explicitly as a 2^9+ x 2^9+ matrix, and then running that program with the qvm.

Thanks!

Measuring and Storing

For the code:

p = pq.Program()
p.inst(X(0)).measure(0,1)
print qvm.run(p, [1,0,2])

I would think that the program takes 1 (X[0]), invert it, and print the result as [[0,0,0]].
But the result is [[1,0,0]]. How is this happening?

extract_qubits errors on Qubit objects

The following errors:

import pyquil.quil as pq
from pyquil.gates import X
p = Program()
p.inst(X(p.alloc()))
p.synthesize()
p.extract_qubits()

This also brings to light the question of how we want to handle un-synthesized programs. Calling print and running Programs synthesize them automatically, but as it is the above will error for a different reason if we omit the p.synthesize line. (as will asking for p.actions)

pyquil-config-setup script does not work

The python 3 compatibility code in pyquil/setup/config.py seems to be wonky. The try/except block can't be inside a function body for that to work. A better alternative: delete the try/except check and add ...

import six
input = six.moves.input

JobResult is_done should also query for an update

Right now the .is_done() method on a jobresult doesn't query for an update. This means to see if a job is done you need to run:

while not res.is_done():
    res.get()
    time.sleep(0.5)

It makes sense to me that an improvement would be to have is_done() query for status itself.

while not res.is_done():
    time.sleep(0.5)

Minor doc issues seen from running QPU

Chris and I have been walking through the instructions as a double check. I noticed two things:

  1. In the T2 Ramsey section we are missing instructions to
    from pyquil.plots import T2RamseyModel
  2. Also, in the box:
x, y = res_ramsey.decode()
fit_n_data = model.report_fit(np.asarray(x), np.asarray(y))
fit, data = (fit_n_data[0], fit_n_data[1:])
fit.plot()
plt.show()
print fit.fit_report()```
The
```fit.plot(); plt.show()```
actually does not work. I had to use
```fig=fit.plot(); fig[0].show()```

And we should add a note to use the `https:\\job.rigetti.com\beta` endpoint

Program comparison

Compare two programs for equality. For simplicity start with programs built with protoquil.

'raise_on_status' in Python 3.5.2

Even after downgrading requests to 2.7.0 the connection won't sync in Python 3.5.2. Runs fine in Python 2.7 though.


TypeError Traceback (most recent call last)
in ()
1 from pyquil.quil import Program
2 import pyquil.api as api
----> 3 qvm = api.SyncConnection()

/usr/local/lib/python3.5/dist-packages/pyquil/api.py in init(self, endpoint, api_key, user_id, gate_noise, measurement_noise, num_retries, random_seed)
206 status_forcelist=[502, 503, 504, 521, 523],
207 backoff_factor=0.2,
--> 208 raise_on_status=False))
209 self.session.mount("http://", retry_adapter)
210 self.session.mount("https://", retry_adapter)

TypeError: init() got an unexpected keyword argument 'raise_on_status'

Dagger a program

A method that accepts a program and returns the inverse of that program.

Requirements:
[ ] Check if Program is a valid set of Protoquil (no control flow, no measurement)
[ ] Returns new Program object that is the inverse of the program.

Error when using is_done() with JobConnection

Error indicates that 'jobId' key is not found in self.result dictionary. My beta key for the api works, as I've tested and ran several programs using api.SyncConnection() Here's the traceback:

File "test.py", line 17, in main
while not res.is_done():
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/pyquil/job_results.py", line 47, in is_done
self.get()
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/pyquil/job_results.py", line 63, in get
return self.qpu.get_job(self)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/pyquil/api.py", line 296, in get_job
url = self.endpoint + ("/job/%s" % (job_result.job_id()))
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/pyquil/job_results.py", line 55, in job_id
return self.result['jobId']
KeyError: 'jobId'

My source code was basically copied from the tutorial for testing purposes:

import pyquil.quil as pq
from pyquil.quil import Program
import pyquil.api as api
from pyquil.gates import *
from numpy import *
import sys
sys.path.append('/usr/local/lib/python2.7/site-packages')
import nlopt
from pyquil.api import JobConnection
import time

job_qvm = JobConnection(endpoint="https://job.rigetti.com/beta")
#qvm = api.SyncConnection()

def main():
ย ย ย ย  res = job_qvm.run(Program(X(0)).measure(0, 0), [0])
ย ย ย ย  while not res.is_done():
ย ย ย ย ย ย ย ย  time.sleep(1)
ย ย ย ย  print(res.get())
ย ย ย ย  return 0

main()

p.inst(q) for alloc'd qubit gives bad error message

Is this expected behavior?

from pyquil.quil import Program
p = Program()
q = p.alloc()
# The following works fine...
p.inst(('X', q))
# No dice
p.inst(['X', q])
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "/home/ampolloreno/repos/pyquil/pyquil/quilbase.py", line 283, in inst
    self.inst(*instruction)
  File "/home/ampolloreno/repos/pyquil/pyquil/quilbase.py", line 308, in inst
    raise TypeError("Invalid instruction: {}".format(instruction))
  File "/home/ampolloreno/repos/pyquil/pyquil/resource_manager.py", line 84, in __str__
    return str(self.index())
  File "/home/ampolloreno/repos/pyquil/pyquil/resource_manager.py", line 77, in index
    raise RuntimeError("Can't get the index of an unassigned qubit.")
RuntimeError: Can't get the index of an unassigned qubit.

Program if_then doesn't inherit defined gates

Programs don't automatically inherit the defined gates of the programs they use as branches for "if_then" control. That is, the following code throws an error on the QVM:

p1 = pq.Program()
p1.inst(H(0))
p1.measure(0, 0)

p2 = pq.Program()
p2.defgate("A", np.array([[1,0],[0,1]]))
p2.inst(("A", 0))

p3 = pq.Program()
p3.defgate("B", np.array([[0,1],[1,0]]))
p3.inst(("B", 0))

p1.if_then(0, p2, p3)

cxn.run(p1, [0])

The program p1 doesn't inherit the gates "A" and "B" from p2 and p3, unless the user manually tells it to:

p1.defined_gates += p2.defined_gates
p1.defined_gates += p3.defined_gates

PyQuil not Python3.6 compatible.

Creating an automated python 3 test environment with tox revealed several incompatibilities with python3.6. Attached is the error report generated using the tox build.

platform linux -- Python 3.6.1+, pytest-3.1.2, py-1.4.34, pluggy-0.4.0
rootdir: /home/runner/pyquil, inifile:
plugins: cov-2.5.1
collected 98 items

pyquil/tests/test_forest.py ........F
pyquil/tests/test_job_results.py ..
pyquil/tests/test_parametric.py .......F
pyquil/tests/test_paulis.py ....................F........
pyquil/tests/test_qpu.py FFFF
pyquil/tests/test_quil.py .........................................
pyquil/tests/test_resource_manager.py ..
pyquil/tests/test_wavefunction.py ...

----------- coverage: platform linux, python 3.6.1-final-0 -----------
Name                                    Stmts   Miss  Cover
-----------------------------------------------------------
pyquil/__init__.py                          0      0   100%
pyquil/api.py                             192     50    74%
pyquil/gates.py                            90      5    94%
pyquil/job_results.py                      80     34    58%
pyquil/parametric.py                       40      4    90%
pyquil/paulis.py                          288      7    98%
pyquil/plots.py                           108    108     0%
pyquil/qpu.py                              77     34    56%
pyquil/quil.py                             62      1    98%
pyquil/quil_atom.py                         3      0   100%
pyquil/quilbase.py                        380     58    85%
pyquil/resource_manager.py                 89      9    90%
pyquil/slot.py                             47      3    94%
pyquil/tests/test_forest.py                77      4    95%
pyquil/tests/test_job_results.py           14      0   100%
pyquil/tests/test_parametric.py           110      1    99%
pyquil/tests/test_paulis.py               293     30    90%
pyquil/tests/test_qpu.py                   54     16    70%
pyquil/tests/test_quil.py                 244      9    96%
pyquil/tests/test_resource_manager.py      26      0   100%
pyquil/tests/test_wavefunction.py          25      0   100%
pyquil/wavefunction.py                     52      3    94%
-----------------------------------------------------------
TOTAL                                    2351    376    84%


============================================================================ FAILURES =============================================================================
________________________________________________________________________ test_wavefunction ________________________________________________________________________

cxn_wf = <pyquil.api.SyncConnection object at 0x7f8e03f9ec18>, prog_wf = <pyquil.quil.Program object at 0x7f8e03f9e4a8>

    def test_wavefunction(cxn_wf, prog_wf):
>       wf, mem = cxn_wf.wavefunction(prog_wf, [0, 1])

pyquil/tests/test_forest.py:130:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
pyquil/api.py:365: in wavefunction
    return self.process_wavefunction_response(res, payload)
pyquil/api.py:508: in process_wavefunction_response
    return recover_complexes(res.content, classical_addresses=payload['addresses'])
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

coef_string = b'\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00...0\x00?\xe6\xa0\x9ef\x7f;\xcc\x00\x00\x00\x00\x00\x00\x00\x00\xbf\xe6\xa0\x9ef\x7f;\xcc\x00\x00\x00\x00\x00\x00\x00\x00'
classical_addresses = [0, 1]

    def recover_complexes(coef_string, classical_addresses):
        """
        From a bit packed string, unpacks to get the wavefunction and classical measurement results
        :param coef_string:
        :param classical_addresses:
        :return:
        """
        num_octets = len(coef_string)
        num_addresses = len(classical_addresses)
        num_memory_octets = _round_to_next_multiple(num_addresses, 8) // 8
        num_wavefunction_octets = num_octets - num_memory_octets

        # Parse the classical memory
        mem = []
        for i in range(num_memory_octets):
>           octet = struct.unpack('B', coef_string[i])[0]
E           TypeError: a bytes-like object is required, not 'int'

pyquil/job_results.py:109: TypeError
___________________________________________________________________ test_exponentiate_paraprog ____________________________________________________________________

    def test_exponentiate_paraprog():
        xterm = PauliTerm("X", 2)*PauliTerm("X", 1)
        paraprog = exponential_map(xterm)
        prog = paraprog(1)
>       assert prog.out() == "H 1\nH 2\nCNOT 1 2\nRZ(2.0) 2\nCNOT 1 2\nH 1\nH 2\n"
E       AssertionError: assert 'H 2\nH 1\nCN...1\nH 2\nH 1\n' == 'H 1\nH 2\nCNO...2\nH 1\nH 2\n'
E         + H 1
E           H 2
E         + CNOT 1 2
E         + RZ(2.0) 2
E         + CNOT 1 2
E           H 1
E         - CNOT 2 1...
E
E         ...Full output truncated (5 lines hidden), use '-vv' to show

pyquil/tests/test_parametric.py:166: AssertionError
________________________________________________________________________ test_exponentiate ________________________________________________________________________

    def test_exponentiate():
        # test rotation of single qubit
        generator = PauliTerm("Z", 0, 1.0)
        para_prog = exponential_map(generator)
        prog = para_prog(1)
        result_prog = Program().inst(RZ(2.0)(0))
        compare_progs(prog, result_prog)

        # testing general 2-circuit
        generator = PauliTerm("Z", 1, 1.0) * PauliTerm("Z", 0, 1.0)
        para_prog = exponential_map(generator)
        prog = para_prog(1)
        result_prog = Program().inst(CNOT(0, 1)).inst(RZ(2.0)(1)).inst(CNOT(0, 1))
>       compare_progs(prog, result_prog)

pyquil/tests/test_paulis.py:249:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

test = <pyquil.quil.Program object at 0x7f8e040c6390>, reference = <pyquil.quil.Program object at 0x7f8e0419b6d8>

    def compare_progs(test, reference):
        """
        compares two programs gate by gate, param by param
        """
        tinstr = test.actions
        rinstr = reference.actions
        assert len(tinstr) == len(rinstr)
        for idx in range(len(tinstr)):
            # check each field of the instruction object
            assert tinstr[idx][1].operator_name == rinstr[idx][1].operator_name
            assert len(tinstr[idx][1].parameters) == len(rinstr[idx][1].parameters)
            for pp in range(len(tinstr[idx][1].parameters)):
                cmp_val = isclose(tinstr[idx][1].parameters[pp], rinstr[idx][1].parameters[pp])
                assert cmp_val

            assert len(tinstr[idx][1].arguments) == len(rinstr[idx][1].arguments)
            for aa in range(len(tinstr[idx][1].arguments)):
>               assert tinstr[idx][1].arguments[aa] == rinstr[idx][1].arguments[aa]
E               assert <DirectQubit 1> == <DirectQubit 0>

pyquil/tests/test_paulis.py:50: AssertionError
__________________________________________________________________________ test_qpu_rabi __________________________________________________________________________

sample_config = {'devices': [{'name': 'Z12-13-C4a2', 'qubits': [{'num': 2, 'rabi_params': {'start': 0.01, 'step': 0.2, 'stop': 20, 'ti...e': 160.0}, 'ramsey_params': {'detuning': 0.5, 'start': 0.01, 'step': 0.2, 'stop': 20}, 'ssr_fidelity': 0.923, ...}]}]}

    def test_qpu_rabi(sample_config):
        with mock.patch('pyquil.qpu.get_info') as m_get_info:
            m_get_info.return_value = sample_config
            with mock.patch.object(QPUConnection, "post_json") as m_post:
                mocked_response = {'jobId': "ASHJKSDUK", 'result': [[1]]}
                m_post.return_value.content = json.dumps(mocked_response)
                device_name = "Z12-13-C4a2"
                qpu = QPUConnection(device_name)
>               qpu.rabi(2)

pyquil/tests/test_qpu.py:57:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
pyquil/qpu.py:40: in rabi
    payload = get_rabi_params(self.device_name, qubit_id)
pyquil/qpu.py:152: in get_rabi_params
    return get_params(device_name, qcid, rabi_parse)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

device_name = 'Z12-13-C4a2', qcid = 2, func = <function get_rabi_params.<locals>.rabi_parse at 0x7f8e04159ae8>

    def get_params(device_name, qcid, func):
        """
        Get and parse the configuration information from the Forest API.
        :param str device_name: The device to get info for
        :param int qcid: The qubit number to look at
        :param func: A function to apply to the qubit specific JSON dictionary of config info
        :return:
        """
        config_dict = get_info()
        try:
>           device_config = filter(lambda dd: dd['name'] == device_name, config_dict['devices'])[0]
E           TypeError: 'filter' object is not subscriptable

pyquil/qpu.py:126: TypeError
_________________________________________________________________________ test_qpu_ramsey _________________________________________________________________________

sample_config = {'devices': [{'name': 'Z12-13-C4a2', 'qubits': [{'num': 2, 'rabi_params': {'start': 0.01, 'step': 0.2, 'stop': 20, 'ti...e': 160.0}, 'ramsey_params': {'detuning': 0.5, 'start': 0.01, 'step': 0.2, 'stop': 20}, 'ssr_fidelity': 0.923, ...}]}]}

    def test_qpu_ramsey(sample_config):
        with mock.patch('pyquil.qpu.get_info') as m_get_info:
            m_get_info.return_value = sample_config
            with mock.patch.object(QPUConnection, "post_json") as m_post:
                mocked_response = {'jobId': "ASHJKSDUK", 'result': [[1]]}
                m_post.return_value.content = json.dumps(mocked_response)
                device_name = "Z12-13-C4a2"
                qpu = QPUConnection(device_name)
>               qpu.ramsey(3)

pyquil/tests/test_qpu.py:75:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
pyquil/qpu.py:57: in ramsey
    payload = get_ramsey_params(self.device_name, qubit_id)
pyquil/qpu.py:171: in get_ramsey_params
    return get_params(device_name, qcid, ramsey_parse)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

device_name = 'Z12-13-C4a2', qcid = 3, func = <function get_ramsey_params.<locals>.ramsey_parse at 0x7f8e04159d90>

    def get_params(device_name, qcid, func):
        """
        Get and parse the configuration information from the Forest API.
        :param str device_name: The device to get info for
        :param int qcid: The qubit number to look at
        :param func: A function to apply to the qubit specific JSON dictionary of config info
        :return:
        """
        config_dict = get_info()
        try:
>           device_config = filter(lambda dd: dd['name'] == device_name, config_dict['devices'])[0]
E           TypeError: 'filter' object is not subscriptable

pyquil/qpu.py:126: TypeError
___________________________________________________________________________ test_qpu_t1 ___________________________________________________________________________

sample_config = {'devices': [{'name': 'Z12-13-C4a2', 'qubits': [{'num': 2, 'rabi_params': {'start': 0.01, 'step': 0.2, 'stop': 20, 'ti...e': 160.0}, 'ramsey_params': {'detuning': 0.5, 'start': 0.01, 'step': 0.2, 'stop': 20}, 'ssr_fidelity': 0.923, ...}]}]}

    def test_qpu_t1(sample_config):
        with mock.patch('pyquil.qpu.get_info') as m_get_info:
            m_get_info.return_value = sample_config
            with mock.patch.object(QPUConnection, "post_json") as m_post:
                mocked_response = {'jobId': "ASHJKSDUK", 'result': [[1]]}
                m_post.return_value.content = json.dumps(mocked_response)
                device_name = "Z12-13-C4a2"
                qpu = QPUConnection(device_name)
>               qpu.t1(2)

pyquil/tests/test_qpu.py:93:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
pyquil/qpu.py:74: in t1
    payload = get_t1_params(self.device_name, qubit_id)
pyquil/qpu.py:189: in get_t1_params
    return get_params(device_name, qcid, t1_parse)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

device_name = 'Z12-13-C4a2', qcid = 2, func = <function get_t1_params.<locals>.t1_parse at 0x7f8e040be0d0>

    def get_params(device_name, qcid, func):
        """
        Get and parse the configuration information from the Forest API.
        :param str device_name: The device to get info for
        :param int qcid: The qubit number to look at
        :param func: A function to apply to the qubit specific JSON dictionary of config info
        :return:
        """
        config_dict = get_info()
        try:
>           device_config = filter(lambda dd: dd['name'] == device_name, config_dict['devices'])[0]
E           TypeError: 'filter' object is not subscriptable

pyquil/qpu.py:126: TypeError
_________________________________________________________________________ test_get_params _________________________________________________________________________

sample_config = {'devices': [{'name': 'Z12-13-C4a2', 'qubits': [{'num': 2, 'rabi_params': {'start': 0.01, 'step': 0.2, 'stop': 20, 'ti...e': 160.0}, 'ramsey_params': {'detuning': 0.5, 'start': 0.01, 'step': 0.2, 'stop': 20}, 'ssr_fidelity': 0.923, ...}]}]}

    def test_get_params(sample_config):
        with mock.patch('pyquil.qpu.get_info') as m_get_info:
            m_get_info.return_value = sample_config
>           assert get_rabi_params("Z12-13-C4a2", 2) == {'start': 0.01, 'stop': 20, 'step': 0.2,
                                                         'time': 160.}

pyquil/tests/test_qpu.py:110:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
pyquil/qpu.py:152: in get_rabi_params
    return get_params(device_name, qcid, rabi_parse)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

device_name = 'Z12-13-C4a2', qcid = 2, func = <function get_rabi_params.<locals>.rabi_parse at 0x7f8e04159d90>

    def get_params(device_name, qcid, func):
        """
        Get and parse the configuration information from the Forest API.
        :param str device_name: The device to get info for
        :param int qcid: The qubit number to look at
        :param func: A function to apply to the qubit specific JSON dictionary of config info
        :return:
        """
        config_dict = get_info()
        try:
>           device_config = filter(lambda dd: dd['name'] == device_name, config_dict['devices'])[0]
E           TypeError: 'filter' object is not subscriptable

pyquil/qpu.py:126: TypeError
=============================================================== 7 failed, 91 passed in 0.93 seconds ===============================================================
ERROR: InvocationError: '/home/runner/pyquil/.tox/py36/bin/py.test --cov=pyquil pyquil/tests'
_____________________________________________________________________________ summary _____________________________________________________________________________
ERROR:   py36: commands failed```

No designated zero element

Currently we have an ID element, which seems to me to be a useful idea, but we don't have a ZERO element, which means that initializing empty PauliSums ends up feeling a little hacky. I think having a ZERO element would make sense.

Allocating qubits "owned" by one Program to another

The following code produces behavior that I don't think is expected:

from pyquil.quil import Program
from pyquil.gates import X
p = Program()
q = p.alloc()
r = Program()
r.inst(X(q)) # Should I even be allowed to do this?
assert not r.resource_manager.live_qubits and not r.resource_manager.dead_qubits

Shouldn't one of those lists be populated, or do I not understand how the ResourceManager is designed?

Bar Charts for wavefunction probabilities

We often want to display the wavefunction as a plot. Best would be to have a built-in bar chart for wavefunctions:

wav, _ = qvm.wavefunction(p, [0])
wav.plot()
wav.plot(qubit_subset=[0, 2, 8])

This would plot a bar chart with bitstring on the x axis and probability on the y axis.

The second option could restrict to plotting a subset of the Hilbert space. As the number grows exponentially this is useful for ignoring the ancilla qubits, etc.

HTTP 500 error ... no applicable method ...

Hi, I'm seeing the following HTTP 500 error:

There is no applicable method for the generic function
  #<STANDARD-GENERIC-FUNCTION CL-QUIL::PRINT-INSTRUCTION (24)>
when called with arguments
  (18 #<SYNONYM-STREAM :SYMBOL SB-SYS:*STDOUT* {1000014153}>).
...
requests.exceptions.HTTPError: 500 Server Error: Internal Server Error for url: https://api.rigetti.com/qvm

Here's a repro:

import pyquil.forest as qvm
import pyquil.quil as pq

def prog_from_file(filepath):
    """Make a Program from a file
    """
    p = pq.Program()
    with open(filepath) as fp:
        for line in fp:
            p.inst(line.rstrip('\n'))
    return p

if __name__ == '__main__':
    p = prog_from_file('/path/to/repro.quil')  # cleaner way to get a Program from a file?
    print p
    print qvm.Connection().run_and_measure(p, [2,3], 1)
    #print qvm.Connection().run(p, [2,3], 1)  # note that run appears to work

repro.quil:

X 5
X 0
H 1
CNOT 1 2
H 3
CNOT 3 4
CNOT 3 2
CNOT 5 4
H 5
MEASURE 5 [5]
MEASURE 4 [4]
CNOT 0 1
H 0
MEASURE 0 [0]
MEASURE 1 [1]
CNOT 3 2
JUMP-WHEN @THEN1 [1]
JUMP @END2
LABEL @THEN1
X 2
LABEL @END2
JUMP-WHEN @THEN7 [4]
JUMP @END8
LABEL @THEN7
X 3
LABEL @END8
JUMP-WHEN @THEN3 [0]
JUMP @END4
LABEL @THEN3
Z 2
LABEL @END4
JUMP-WHEN @THEN5 [5]
JUMP @END6
LABEL @THEN5
Z 3
LABEL @END6
CNOT 2 3

@tarballs-are-good Any clarification on the error and what triggers it? Thanks!

equality testing between pauliterms and paulisums fails

>>> from pyquil.paulis import PauliTerm
>>> a = PauliTerm('X', 0) + PauliTerm('Y', 1)
>>> a == PauliTerm('Y', 0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/ampolloreno/repos/pyquil/pyquil/paulis.py", line 348, in __eq__
    return self == PauliSum(other)
  File "/home/ampolloreno/repos/pyquil/pyquil/paulis.py", line 332, in __init__
    raise ValueError("PauliSum's are currently constructed from Sequences of PauliTerms.")
ValueError: PauliSum's are currently constructed from Sequences of PauliTerms.

This should just return False.

Does allocating qubits on many programs work as expected?

Is this the behavior we expect?

>>> from pyquil.quil import Program
>>> from pyquil.gates import X
>>> p = Program()
>>> p.inst(X(1))
<pyquil.quil.Program object at 0x7f28fc5ce1d0>
>>> p = Program()
>>> q = Program()
>>> r = Program()
>>> a = p.alloc()
>>> b = q.alloc()
>>> p.inst(X(a))
<pyquil.quil.Program object at 0x7f28f1e0d110>
>>> q.inst(X(b))
<pyquil.quil.Program object at 0x7f28f1e0d050>
>>> r.inst(X(a), X(b))
<pyquil.quil.Program object at 0x7f28f1e27a50>
>>> print p
X 0
>>> print q
X 0
>>> print r
X 0
X 0

Somehow I think p and q should have different qubits allocated to them, such that r reads

X 0
X 1

right?
@stevenheidel @jotterbach @willzeng

Clarification on "state_prep" usage convention

Hi. I'm working through your tutorial on using Forest (thanks for offering it out): http://pyquil.readthedocs.io/en/latest/getting_started.html#installation-and-getting-started

I wanted to clarify a usage convention. In the section on the Quantum Fourier Transform, the state is prepared for use with a 3-qubit QFT function. However, the state is only initialized for qubit-0 before being passed to the execution section:
wavf, _ = qvm.wavefunction(state_prep + qft3(0, 1, 2))
print(wavf.amplitudes)

However, in the section just above this, there is a comment:
"We can verify that this works by computing its wavefunction. However, we need to add some โ€œdummyโ€ qubits, because otherwise wavefunction would return a two-element vector."

I might be misunderstanding the meaning in the documentation, but I'm not too clear on when you are required to pass in the fully defined state-vector (all states defined, even if you need to use dummy identity operators etc.) and when just a single one will work, even though you are applying it to a 3-qubit function for example as in this case.
Thanks for any clarification. Once again, thanks for open-sourcing out this great set of tools and capabilities.
Thanks.

defgate: No validation whether the matrix is unitary

Hi,

This is not a feature request, I'm just trying to wrap my head around the infrastructure - if this is not the right place to ask, please let me know where I can ask learning questions as a total newbie to quantum computing and the Rigetti stack.

I was wondering what is the reason behind that I can create a quantum gate based on a non-unitary matrix? Is this something I'd have to be careful about in the future as well, or Forest is planned to have a feature to validate against non-unitary operators? Also, it's one thing that it can run on the QVM - but how would this operate on a real quantum processor?

>>> import pyquil.quil as pq 
>>> import numpy as np
>>> import pyquil.forest as forest
>>> qvm = forest.Connection()
>>> non_unitary_mx =np.array(([1.0, 2.0], [3.0, 4.0]))
>>> bad_prog = pq.Program().defgate("NON-UNITARY-BAD-GATE", non_unitary_mx)
>>> bad_prog.inst(("NON-UNITARY-BAD-GATE",0))
<pyquil.quil.Program object at 0x1096e92d0>
>>> bad_prog.inst(("NON-UNITARY-BAD-GATE",1))
<pyquil.quil.Program object at 0x1096e92d0>
>>> print bad_prog
DEFGATE NON-UNITARY-BAD-GATE:
    1.0, 2.0
    3.0, 4.0

NON-UNITARY-BAD-GATE 0
NON-UNITARY-BAD-GATE 1

>>> print qvm.wavefunction(bad_prog)
(array([ 1.+0.j,  3.+0.j,  3.+0.j,  9.+0.j]), [])

Python 3 compatibility?

I didn't see it stated anywhere but it seems pyQuil is python 2 only. I started to make some fixes on a branch but quickly ran into deeper issues.

Any plans or roadblocks for Python 3 compatibility? It seems a shame to start a new project as Python 2 only.

Initialize PauliTerms with more than one Pauli op

In order to produce an PauliTerm such as X0Y1Z5 one must specify each PauliTerm atomic element individually and multiply them together. It would be easier to specify the tensor product in one go by passing a tuple of tuples representing the (operator, index) pairs.

Proposed mode of operation

pterm = PauliTerm([("X, 0), ("Y", 1), ("Z", 5)])

would be equivalent to the current way of constructing X0Y1Z5

pterm = PauliTerm("X", 0)*PauliTerm("Y", 1)*PauliTerm("Z", 5)

Wavefunction decoding for JobConnections isn't decoding properly

Running a wavefunction command on a JobConnection object gets a result that looks like the byte information hasn't been properly decoded:

from pyquil.quil import Program
from pyquil.gates import *
import pyquil.api as api

cxn = api.JobConnection(endpoint="https://job.rigetti.com/beta")
res = cxn.wavefunction(Program(X(0)))
# wait for a bit
print res.get()
{u'result': u'AAAAAAAAAAAAAAAAAAAAAD/wAAAAAAAAAAAAAAAAAAA=', u'jobId': u'HMYHUBMJPM'}

This is on pyquil's current master branch.

HTTP 500 error ... Couldn't find match at position 14

Hi, I'm seeing the following HTTP 500 error:

Couldn't find match at position 14 within the lexer CL-QUIL::LINE-LEXER.
...
requests.exceptions.HTTPError: 500 Server Error: Internal Server Error for url: https://api.rigetti.com/qvm

Here's a small repro:

from pyquil.quil import Program
import pyquil.forest as qvm
from pyquil.gates import X

if __name__ == '__main__':
    cxn = qvm.Connection()
    p = Program([
        "DEFCIRCUIT FOO Q:",
        "    MEASURE Q [Q]"])
    print p
    print cxn.run(p.inst(X(0)).inst("FOO 0"), [0], 1)

@tarballs-are-good, the lexer appears not to like [Q] in the above, is this a server issue or not legal Quil? (HTTP status code of 400 would more clearly signal that it's a client issue rather than a server issue in the latter case)

Position 14 presumably only refers to the offset within the offending line, suggest including the offending line (or its number) in the error message to make the problem much easier to isolate in bigger circuits.

Thanks!

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.