Copyright 2018 QuTech Delft. Licensed under the Apache License, Version 2.0.
For more information on Quantum Inspire, see https://www.quantum-inspire.com/. For more information on ProjectQ, see https://github.com/ProjectQ-Framework/ProjectQ.
import logging
from coreapi.auth import BasicAuthentication
from getpass import getpass
from projectq import MainEngine
from projectq.setups import linear
from projectq.cengines import ManualMapper
from projectq.ops import H, Rx, Rz, CNOT, CZ, Measure, All
from quantuminspire.api import QuantumInspireAPI
from quantuminspire.projectq.backend_qx import QIBackend
if 'password' not in vars().keys():
print('Enter email')
username = input()
print('Enter password')
password = getpass()
uri = r'https://api.quantum-inspire.com/'
authentication = BasicAuthentication(username, password)
qi_api = QuantumInspireAPI(uri, authentication)
projectq_backend = QIBackend(quantum_inspire_api=qi_api)
We create an algorithm to entangle qubit 0 and qubit 4.
engine_list = [ManualMapper(lambda ii: ii)]
engine = MainEngine(backend=projectq_backend, engine_list=engine_list) # create default compiler (simulator back-end)
qubits = engine.allocate_qureg(5)
q1 = qubits[0]
q2 = qubits[-1]
H | q1 # apply a Hadamard gate
CNOT | (q1, q2)
All(Measure) | qubits # measure the qubits
engine.flush() # flush all gates (and execute measurements)
print("Measured {}".format(','.join([str(int(q)) for q in qubits])))
print('Probabilities: %s' % (projectq_backend.get_probabilities(qubits),))
print(projectq_backend.cqasm())
Measured 0,0,0,0,0 Probabilities: {'00000': 0.4931640625, '10001': 0.5068359375} version 1.0 # generated by Quantum Inspire <class 'quantuminspire.projectq.backend_qx.QIBackend'> class qubits 5 h q[0] CNOT q[0], q[4]
The result is as expected: about half of the results is split between 0 and 1 on qubit 0 and 4. The QASM generated by the backend is fairly simple.
On a spin-qubit array we have limited connectivity and also a limited set of gates available. With ProjectQ we can handle these cases by adding specific compiler engines.
Our engine lists is generated by the projectq.setups.linear
module.
engine_list = linear.get_engine_list(num_qubits=5, one_qubit_gates=(Rx, Rz), two_qubit_gates=(CZ,))
engine = MainEngine(backend=projectq_backend, engine_list=engine_list) # create default compiler (simulator back-end)
qubits = engine.allocate_qureg(5)
q1 = qubits[0]
q2 = qubits[-1]
H | q1 # apply a Hadamard gate
CNOT | (q1, q2)
All(Measure) | qubits # measure the qubits
engine.flush() # flush all gates (and execute measurements)
print("Measured {}".format(','.join([str(int(q)) for q in qubits])))
print('Probabilities: %s' % (projectq_backend.get_probabilities(qubits),))
print(projectq_backend.cqasm())
Measured 0,0,0,0,0 Probabilities: {'00000': 0.484375, '10001': 0.515625} version 1.0 # generated by Quantum Inspire <class 'quantuminspire.projectq.backend_qx.QIBackend'> class qubits 5 h q[0] CNOT q[0], q[4]
The result is the same, but if we look at the QASM generated there is quite a difference. The CNOT gate was replaced by a CZ gate with some single qubit operations. Also the qubits 0 and 4 have been mapped to neighboring qubits.
current_mapping = engine.mapper.current_mapping
for l, p in current_mapping.items():
print('mapping logical qubit %d to physical qubit %d' % (l, p))
mapping logical qubit 0 to physical qubit 0 mapping logical qubit 1 to physical qubit 1 mapping logical qubit 2 to physical qubit 2 mapping logical qubit 3 to physical qubit 3 mapping logical qubit 4 to physical qubit 4