ProjectQ Demo

Compiling code for IBM QE

Import the IBM setup, the gates, and the compiler engine:


In [1]:
import projectq.setups.ibm # Imports the default compiler to map to IBM QE
from projectq.backends import IBMBackend
from projectq.ops import All, Entangle, Measure
from projectq import MainEngine

Create the compiler using the default compiler engines for the IBM backend and allocate a quantum register of 3 qubits:


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

Entangle the quantum register:


In [3]:
Entangle | qureg

Measure the quantum register and run the circuit:


In [4]:
All(Measure) | qureg
engine.flush()


- Authenticating...
IBM QE user (e-mail) > dsteiger@phys.ethz.ch
IBM QE password > ········
- Running code: 
include "qelib1.inc";
qreg q[3];
creg c[3];
h q[2];
cx q[2], q[0];
h q[1];
cx q[1], q[0];
h q[0];
measure q[0] -> c[0];
h q[2];
measure q[2] -> c[2];
h q[1];
measure q[1] -> c[1];
- Waiting for results...
- Done.
11100 with p = 0.388671875*
01100 with p = 0.0478515625
10000 with p = 0.0029296875
00000 with p = 0.4482421875
01000 with p = 0.0166015625
11000 with p = 0.025390625
00100 with p = 0.0263671875
10100 with p = 0.0439453125

Output the measurement result:


In [5]:
print([int(q) for q in qureg])


[1, 1, 1]

Inspecting the gates required for a 5-qubit entangle on IBM QE

Create a new compiler with a command printer as a back-end:


In [6]:
from projectq.backends import CommandPrinter
engine2 = MainEngine(CommandPrinter(),
                     engine_list=projectq.setups.ibm.get_engine_list())

Allocate a quantum register of 5 qubits:


In [7]:
qureg2 = engine2.allocate_qureg(5)

Entangle quantum register (and run the circuit):

A 5-qubit entangle operation requires one H gate and 4 CNOTs if the qubit chip would support CNOTs between arbitrary qubits:

H | Qubit[0]
CX | ( Qubit[0], Qubit[1] )
CX | ( Qubit[0], Qubit[2] )
CX | ( Qubit[0], Qubit[3] )
CX | ( Qubit[0], Qubit[4] )

In [8]:
Entangle | qureg2
engine2.flush()


Allocate | Qureg[0]
Allocate | Qureg[1]
H | Qureg[1]
CX | ( Qureg[1], Qureg[0] )
Allocate | Qureg[2]
H | Qureg[2]
CX | ( Qureg[2], Qureg[0] )
Allocate | Qureg[3]
H | Qureg[3]
CX | ( Qureg[3], Qureg[0] )
Allocate | Qureg[4]
H | Qureg[4]
CX | ( Qureg[4], Qureg[0] )
H | Qureg[0]
H | Qureg[1]
H | Qureg[2]
H | Qureg[3]
H | Qureg[4]

As IBM's QE chip does not support CNOTs between arbitrary qubits, the compiler automatically changes the abstract entangle circuit to an equivalent circuit which takes into account the hardware constraints of the IBM QE chip. The resulting circuit is shown above as the output of the command printer.

Simulating a circuit for the IBM QE chip

Create a new compiler with our high-performance quantum simulator as a back-end:

Note

Our Simulator can simulate much larger circuits but here we imported the compiler for the IBM QE chip:

import projectq.setups.ibm

and therefore the compiler will only allow circuits which can be mapped to the IBM QE chip. Running larger simulations is easily possible by using the default compiler (see other example codes)


In [9]:
from projectq.backends import Simulator
engine3 = MainEngine(Simulator())

Allocate a 5-qubit quantum register and apply an entangle operations:


In [10]:
qureg3 = engine3.allocate_qureg(5)
Entangle | qureg3

Measure the quantum register and run the circuit:


In [11]:
All(Measure) | qureg3
engine3.flush()

Output the measurement result:


In [12]:
print([int(q) for q in qureg3])


[0, 0, 0, 0, 0]

In [ ]: