Example to use ProjectQ to run algorithms on Quantum Inspire
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.
[1]:
import os
from projectq import MainEngine
from projectq.setups import linear
from projectq.ops import H, Rx, Rz, CNOT, Measure, All
from quantuminspire.api import QuantumInspireAPI
from quantuminspire.credentials import get_authentication
from quantuminspire.projectq.backend_qx import QIBackend
QI_URL = os.getenv('API_URL', 'https://api.quantum-inspire.com/')
[2]:
authentication = get_authentication()
qi_api = QuantumInspireAPI(QI_URL, authentication)
projectq_backend = QIBackend(quantum_inspire_api=qi_api)
Execute algorithm on QX simulator
We create an algorithm to entangle qubit 0 and qubit 4.
[3]:
engine = MainEngine(backend=projectq_backend) # 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 1,0,0,0,1
Probabilities: {'00000': 0.4921875, '10001': 0.5078125}
version 1.0
# cQASM 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.
Simulate a spin-qubit array
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.
[4]:
projectq_backend = QIBackend(quantum_inspire_api=qi_api)
engine_list = linear.get_engine_list(num_qubits=5, one_qubit_gates=(Rx, Rz), two_qubit_gates=(CNOT,))
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 1,0,0,0,1
Probabilities: {'00000': 0.5048828125, '10001': 0.4951171875}
version 1.0
# cQASM generated by Quantum Inspire <class 'quantuminspire.projectq.backend_qx.QIBackend'> class
qubits 5
rx q[0],1.5707963268
rz q[0],1.5707963268
rx q[0],7.85398163397
cnot q[0], q[1]
The result is the same, but if we look at the QASM generated there is quite a difference. The H gate was replaced by some single qubit operations. Also the qubits 0 and 4 have been mapped to neighboring qubits.
[5]:
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 4 to physical qubit 1
mapping logical qubit 1 to physical qubit 2
mapping logical qubit 2 to physical qubit 3
mapping logical qubit 3 to physical qubit 4
[ ]: