Running ProjectQ code on IBM Q devices

In this tutorial, we will see how to run code on IBM Q devices directly from within ProjectQ. All that is needed is an IBM Q Experience user account. To sign up, visit https://quantumexperience.ng.bluemix.net/.

ProjectQ supports two IBM Q devices called ibmqx4 and ibmqx5 which feature 5 and 16 qubits, respectively. Let us start with entangling the qubits of the 5-qubit device:

Entangling 5 qubits

First, we import all necessary operations (Entangle, measurement), the back-end (IBMBackend), and the main compiler engine (MainEngine). The Entangle operation is defined as a Hadamard gate on the first qubit (creates an equal superposition of |0> and |1>), followed by controlled NOT gates acting on all other qubits controlled on the first.


In [ ]:
%matplotlib inline
import matplotlib.pyplot as plt

In [1]:
import projectq.setups.ibm
from projectq.backends import IBMBackend
from projectq.ops import Measure, Entangle, All
from projectq import MainEngine

Next, we instantiate a main compiler engine using the IBM Q back-end and the predefined compiler engines which take care of the qubit placement, translation of operations, etc.:


In [2]:
eng = MainEngine(IBMBackend(use_hardware=True, num_runs=1024,
                            verbose=False, device='ibmqx4'),
                 engine_list=projectq.setups.ibm.get_engine_list())

If use_hardware is set to False, it will use the IBM Q simulator instead. num_runs specifies the number of samples to collect for statistics, verbose=True would output additional information which may be helpful for debugging, and the device parameter lets users choose between the two devices ("ibmqx4" and "ibmqx5").

With our compiler set up, we can now allocate our qubits, entangle them, measure the outcome, and then flush the entire circuit down the compilation pipeline such that it is executed (and measurements are registered). Note that there are many jobs queued for execution on the IBM Q device and, as a result, our execution times out. We will learn how to retrieve our results despite this time out.


In [3]:
def run_entangle(eng, num_qubits):
    # allocate a quantum register of 5 qubits
    qureg = eng.allocate_qureg(num_qubits)

    # entangle the qureg
    Entangle | qureg

    # measure; should be all-0 or all-1
    All(Measure) | qureg

    # run the circuit
    eng.flush()

    # access the probabilities via the back-end:
    # results = eng.backend.get_probabilities(qureg)
    # for state in results:
    #     print("Measured {} with p = {}.".format(state, results[state]))
    # or plot them directly:
    histogram(eng.backend, qureg)
    plt.show()

    # return one (random) measurement outcome.
    return [int(q) for q in qureg]

run_entangle(eng, num_qubits=5)  # run it


IBM QE user (e-mail) > haenert@phys.ethz.ch
IBM QE password > 
Waiting for results. [Job ID: 5b557df2306393003b746da2]
Currently there are 49 jobs queued for execution on ibmqx4.
Currently there are 48 jobs queued for execution on ibmqx4.
---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
<ipython-input-3-4dfb665c4ebe> in <module>()
     20     return [int(q) for q in qureg]
     21 
---> 22 run_entangle(eng, num_qubits=5)  # run it

<ipython-input-3-4dfb665c4ebe> in run_entangle(eng, num_qubits)
     10 
     11     # run the circuit
---> 12     eng.flush()
     13 
     14     # access the probabilities via the back-end:

/home/thomas/ProjectQ/projectq/cengines/_main.py in flush(self, deallocate_qubits)
    302                 qb = self.active_qubits.pop()
    303                 qb.__del__()
--> 304         self.receive([Command(self, FlushGate(), ([WeakQubitRef(self, -1)],))])

/home/thomas/ProjectQ/projectq/cengines/_main.py in receive(self, command_list)
    264                 then send on)
    265         """
--> 266         self.send(command_list)
    267 
    268     def send(self, command_list):

/home/thomas/ProjectQ/projectq/cengines/_main.py in send(self, command_list)
    286                                              "\n" + repr(last_line[-2]))
    287                 compact_exception.__cause__ = None
--> 288                 raise compact_exception  # use verbose=True for more info
    289 
    290     def flush(self, deallocate_qubits=False):

Exception: Timeout. The ID of your submitted job is 5b557df2306393003b746da2.
 raised in:
'  File "/home/thomas/ProjectQ/projectq/backends/_ibm/_ibm_http_client.py", line 174, in _get_result'
'    .format(execution_id))'

Retrieving a timed-out execution

Sometimes, the queue is very long and the waiting times may exceed the limit of 5 minutes. In this case, ProjectQ will raise an exception which contains the job ID, as could be seen above, where the job ID was 5b557df2306393003b746da2.

In order to still retrieve all results at a later point in time, one can simply re-run the entire program using a slightly modified back-end:


In [4]:
eng = MainEngine(IBMBackend(use_hardware=True, num_runs=1024,
                            verbose=False, device='ibmqx4',
                            retrieve_execution="5b557df2306393003b746da2"),  # provide job ID
                 engine_list=projectq.setups.ibm.get_engine_list())

run_entangle(eng, num_qubits=5)


IBM QE user (e-mail) > haenert@phys.ethz.ch
IBM QE password > 
Waiting for results. [Job ID: 5b557df2306393003b746da2]
Measured 00001 with p = 0.0185546875.
Measured 01101 with p = 0.00390625.
Measured 10001 with p = 0.0107421875.
Measured 11001 with p = 0.0029296875.
Measured 10101 with p = 0.0107421875.
Measured 11101 with p = 0.0419921875.
Measured 00011 with p = 0.005859375.
Measured 01011 with p = 0.00390625.
Measured 00111 with p = 0.0029296875.
Measured 01111 with p = 0.0107421875.
Measured 10011 with p = 0.0322265625.
Measured 11011 with p = 0.0419921875.
Measured 10111 with p = 0.056640625.
Measured 11111 with p = 0.2744140625.
Measured 00000 with p = 0.392578125.
Measured 01000 with p = 0.0029296875.
Measured 00100 with p = 0.01171875.
Measured 01100 with p = 0.0126953125.
Measured 10000 with p = 0.0009765625.
Measured 00010 with p = 0.009765625.
Measured 01010 with p = 0.0009765625.
Measured 00110 with p = 0.0029296875.
Measured 01110 with p = 0.0087890625.
Measured 10010 with p = 0.0029296875.
Measured 11010 with p = 0.0068359375.
Measured 10110 with p = 0.00390625.
Measured 11110 with p = 0.025390625.
Out[4]:
[0, 0, 0, 0, 0]

Entangling more qubits: Using ibmqx5

If you have access to the 16-qubit device as well, you can also use ProjectQ to run your quantum programs on this device. ProjectQ contains a 2D grid mapper, which takes care of the mapping for you. We only have to change two things in order to use the 16-qubit chip as opposed to the 5-qubit chip:

1) Import the new 16-qubit setup which contains the compiler engines for this device

2) Modify the device parameter in the IBMBackend to "ibmqx5"

Therefore, in order to entangle more than 5 qubits, we can simply write


In [5]:
import projectq.setups.ibm16  # import setup which contains the grid mapper
eng = MainEngine(IBMBackend(use_hardware=True, num_runs=1024,
                            verbose=False, device='ibmqx5'),  # use ibmqx5 now
                 engine_list=projectq.setups.ibm16.get_engine_list())  # note: ibm16 setup

and then re-run the example from before via run_entangle(eng, num_qubits). If an execution times out, it can also be retrieved at a later point by providing the additional retrieve_execution="execution_id" parameter to the IBMBackend (but this time with device='ibmqx5').


In [6]:
run_entangle(eng, num_qubits=8)


IBM QE user (e-mail) > haenert@phys.ethz.ch
IBM QE password > 
Waiting for results. [Job ID: 5b5580e0e291fd003ea62acf]
Currently there are 12 jobs queued for execution on ibmqx5.
Currently there are 12 jobs queued for execution on ibmqx5.
Measured 00000000 with p = 0.0234375.
Measured 00100000 with p = 0.017578125.
Measured 01000000 with p = 0.0234375.
Measured 01100000 with p = 0.0087890625.
Measured 00010000 with p = 0.013671875.
Measured 00110000 with p = 0.0126953125.
Measured 01010000 with p = 0.0146484375.
Measured 01110000 with p = 0.013671875.
Measured 00000010 with p = 0.013671875.
Measured 00100010 with p = 0.009765625.
Measured 01000010 with p = 0.0107421875.
Measured 01100010 with p = 0.0068359375.
Measured 00010010 with p = 0.0048828125.
Measured 00110010 with p = 0.0078125.
Measured 01010010 with p = 0.0068359375.
Measured 01110010 with p = 0.0078125.
Measured 00000100 with p = 0.001953125.
Measured 00100100 with p = 0.009765625.
Measured 01000100 with p = 0.0068359375.
Measured 01100100 with p = 0.0048828125.
Measured 00010100 with p = 0.005859375.
Measured 00110100 with p = 0.005859375.
Measured 01010100 with p = 0.001953125.
Measured 01110100 with p = 0.005859375.
Measured 00000110 with p = 0.001953125.
Measured 00100110 with p = 0.005859375.
Measured 01000110 with p = 0.00390625.
Measured 01100110 with p = 0.005859375.
Measured 00010110 with p = 0.0107421875.
Measured 00110110 with p = 0.0009765625.
Measured 01010110 with p = 0.001953125.
Measured 01110110 with p = 0.0029296875.
Measured 10000000 with p = 0.0009765625.
Measured 10100000 with p = 0.0087890625.
Measured 11000000 with p = 0.001953125.
Measured 11100000 with p = 0.0029296875.
Measured 10010000 with p = 0.0029296875.
Measured 10110000 with p = 0.001953125.
Measured 11010000 with p = 0.001953125.
Measured 11110000 with p = 0.0009765625.
Measured 10000010 with p = 0.0009765625.
Measured 10100010 with p = 0.0048828125.
Measured 11000010 with p = 0.0009765625.
Measured 11100010 with p = 0.0029296875.
Measured 10010010 with p = 0.001953125.
Measured 10110010 with p = 0.0087890625.
Measured 11010010 with p = 0.0009765625.
Measured 11110010 with p = 0.0009765625.
Measured 10000100 with p = 0.0009765625.
Measured 10100100 with p = 0.0009765625.
Measured 11000100 with p = 0.0048828125.
Measured 10010100 with p = 0.0048828125.
Measured 10110100 with p = 0.001953125.
Measured 11010100 with p = 0.0029296875.
Measured 11110100 with p = 0.001953125.
Measured 10000110 with p = 0.001953125.
Measured 10100110 with p = 0.001953125.
Measured 11100110 with p = 0.0029296875.
Measured 10010110 with p = 0.001953125.
Measured 10110110 with p = 0.001953125.
Measured 11110110 with p = 0.0048828125.
Measured 00000001 with p = 0.0029296875.
Measured 00100001 with p = 0.0029296875.
Measured 01000001 with p = 0.0029296875.
Measured 01100001 with p = 0.0009765625.
Measured 00110001 with p = 0.00390625.
Measured 01010001 with p = 0.005859375.
Measured 01110001 with p = 0.0009765625.
Measured 00000011 with p = 0.0029296875.
Measured 00100011 with p = 0.0029296875.
Measured 01000011 with p = 0.0009765625.
Measured 01100011 with p = 0.0009765625.
Measured 00010011 with p = 0.0029296875.
Measured 00000101 with p = 0.0029296875.
Measured 00100101 with p = 0.0029296875.
Measured 01000101 with p = 0.001953125.
Measured 01100101 with p = 0.0029296875.
Measured 00110101 with p = 0.001953125.
Measured 01010101 with p = 0.001953125.
Measured 01110101 with p = 0.0029296875.
Measured 00000111 with p = 0.0029296875.
Measured 01100111 with p = 0.0009765625.
Measured 00010111 with p = 0.001953125.
Measured 00110111 with p = 0.0009765625.
Measured 01010111 with p = 0.0009765625.
Measured 01110111 with p = 0.001953125.
Measured 10000001 with p = 0.00390625.
Measured 10100001 with p = 0.001953125.
Measured 11000001 with p = 0.0029296875.
Measured 11100001 with p = 0.0048828125.
Measured 10010001 with p = 0.0048828125.
Measured 10110001 with p = 0.0029296875.
Measured 11010001 with p = 0.001953125.
Measured 11110001 with p = 0.0029296875.
Measured 10000011 with p = 0.0029296875.
Measured 10100011 with p = 0.0048828125.
Measured 11000011 with p = 0.0048828125.
Measured 11100011 with p = 0.0029296875.
Measured 10010011 with p = 0.001953125.
Measured 10110011 with p = 0.001953125.
Measured 11010011 with p = 0.001953125.
Measured 11110011 with p = 0.0029296875.
Measured 10000101 with p = 0.005859375.
Measured 10100101 with p = 0.0107421875.
Measured 11000101 with p = 0.009765625.
Measured 11100101 with p = 0.0029296875.
Measured 10010101 with p = 0.0078125.
Measured 10110101 with p = 0.0068359375.
Measured 11010101 with p = 0.0078125.
Measured 11110101 with p = 0.00390625.
Measured 10000111 with p = 0.0078125.
Measured 10100111 with p = 0.005859375.
Measured 11000111 with p = 0.001953125.
Measured 11100111 with p = 0.0048828125.
Measured 10010111 with p = 0.0048828125.
Measured 10110111 with p = 0.001953125.
Measured 11010111 with p = 0.00390625.
Measured 11110111 with p = 0.0068359375.
Measured 00001000 with p = 0.0087890625.
Measured 00101000 with p = 0.017578125.
Measured 01001000 with p = 0.0107421875.
Measured 01101000 with p = 0.0146484375.
Measured 00011000 with p = 0.0048828125.
Measured 00111000 with p = 0.01171875.
Measured 01011000 with p = 0.0126953125.
Measured 01111000 with p = 0.0146484375.
Measured 00001010 with p = 0.009765625.
Measured 00101010 with p = 0.005859375.
Measured 01001010 with p = 0.0029296875.
Measured 01101010 with p = 0.017578125.
Measured 00011010 with p = 0.0087890625.
Measured 00111010 with p = 0.01171875.
Measured 01011010 with p = 0.0029296875.
Measured 01111010 with p = 0.00390625.
Measured 00001100 with p = 0.0068359375.
Measured 00101100 with p = 0.001953125.
Measured 01001100 with p = 0.005859375.
Measured 01101100 with p = 0.0078125.
Measured 00011100 with p = 0.005859375.
Measured 00111100 with p = 0.00390625.
Measured 01011100 with p = 0.00390625.
Measured 01111100 with p = 0.0068359375.
Measured 00001110 with p = 0.0029296875.
Measured 00101110 with p = 0.00390625.
Measured 01101110 with p = 0.0029296875.
Measured 00011110 with p = 0.0048828125.
Measured 00111110 with p = 0.00390625.
Measured 01011110 with p = 0.001953125.
Measured 01111110 with p = 0.0009765625.
Measured 10001000 with p = 0.001953125.
Measured 10101000 with p = 0.001953125.
Measured 11101000 with p = 0.00390625.
Measured 10011000 with p = 0.0048828125.
Measured 10111000 with p = 0.001953125.
Measured 11011000 with p = 0.001953125.
Measured 10001010 with p = 0.0029296875.
Measured 10101010 with p = 0.001953125.
Measured 11101010 with p = 0.001953125.
Measured 10011010 with p = 0.0009765625.
Measured 10111010 with p = 0.001953125.
Measured 11011010 with p = 0.001953125.
Measured 11111010 with p = 0.001953125.
Measured 10001100 with p = 0.0029296875.
Measured 10101100 with p = 0.00390625.
Measured 11001100 with p = 0.0009765625.
Measured 11101100 with p = 0.0009765625.
Measured 10011100 with p = 0.0029296875.
Measured 10111100 with p = 0.001953125.
Measured 10001110 with p = 0.005859375.
Measured 10101110 with p = 0.001953125.
Measured 11001110 with p = 0.0029296875.
Measured 11101110 with p = 0.001953125.
Measured 10011110 with p = 0.0029296875.
Measured 10111110 with p = 0.001953125.
Measured 11011110 with p = 0.001953125.
Measured 11111110 with p = 0.0029296875.
Measured 00001001 with p = 0.001953125.
Measured 00101001 with p = 0.0029296875.
Measured 01001001 with p = 0.0029296875.
Measured 01101001 with p = 0.0048828125.
Measured 00011001 with p = 0.0048828125.
Measured 01011001 with p = 0.0009765625.
Measured 01111001 with p = 0.00390625.
Measured 00001011 with p = 0.001953125.
Measured 00101011 with p = 0.0029296875.
Measured 01001011 with p = 0.001953125.
Measured 00011011 with p = 0.0009765625.
Measured 01111011 with p = 0.0009765625.
Measured 00001101 with p = 0.0009765625.
Measured 01001101 with p = 0.0009765625.
Measured 00011101 with p = 0.0009765625.
Measured 01011101 with p = 0.0029296875.
Measured 00001111 with p = 0.0009765625.
Measured 00101111 with p = 0.0029296875.
Measured 01001111 with p = 0.0009765625.
Measured 00011111 with p = 0.001953125.
Measured 00111111 with p = 0.0009765625.
Measured 01111111 with p = 0.0009765625.
Measured 10001001 with p = 0.0029296875.
Measured 10101001 with p = 0.00390625.
Measured 11001001 with p = 0.001953125.
Measured 11101001 with p = 0.0068359375.
Measured 10011001 with p = 0.001953125.
Measured 10111001 with p = 0.0029296875.
Measured 11011001 with p = 0.00390625.
Measured 11111001 with p = 0.0068359375.
Measured 10001011 with p = 0.0048828125.
Measured 10101011 with p = 0.00390625.
Measured 11001011 with p = 0.00390625.
Measured 11101011 with p = 0.0029296875.
Measured 10011011 with p = 0.0009765625.
Measured 10111011 with p = 0.001953125.
Measured 11011011 with p = 0.001953125.
Measured 11111011 with p = 0.001953125.
Measured 10001101 with p = 0.0009765625.
Measured 10101101 with p = 0.00390625.
Measured 11101101 with p = 0.0029296875.
Measured 10011101 with p = 0.00390625.
Measured 10111101 with p = 0.0078125.
Measured 11011101 with p = 0.005859375.
Measured 11111101 with p = 0.0048828125.
Measured 10001111 with p = 0.0009765625.
Measured 10101111 with p = 0.001953125.
Measured 11001111 with p = 0.001953125.
Measured 11101111 with p = 0.0078125.
Measured 10011111 with p = 0.0009765625.
Measured 10111111 with p = 0.005859375.
Measured 11011111 with p = 0.00390625.
Measured 11111111 with p = 0.0009765625.
Out[6]:
[0, 0, 1, 0, 0, 0, 1, 0]