{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Example to use ProjectQ to run algorithms on Quantum Inspire" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Copyright 2018 QuTech Delft. Licensed under the Apache License, Version 2.0.\n", "\n", "For more information on Quantum Inspire, see https://www.quantum-inspire.com/.\n", "For more information on ProjectQ, see https://github.com/ProjectQ-Framework/ProjectQ." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import logging\n", "import os\n", "from getpass import getpass\n", "\n", "from projectq import MainEngine\n", "from projectq.setups import linear\n", "from projectq.ops import H, Rx, Rz, CNOT, CZ, Measure, All\n", "\n", "from quantuminspire.credentials import load_account, get_token_authentication, get_basic_authentication\n", "from quantuminspire.api import QuantumInspireAPI\n", "from quantuminspire.projectq.backend_qx import QIBackend\n", "\n", "QI_EMAIL = os.getenv('QI_EMAIL')\n", "QI_PASSWORD = os.getenv('QI_PASSWORD')\n", "QI_URL = os.getenv('API_URL', 'https://api.quantum-inspire.com/')" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "token = load_account()\n", "if token is not None:\n", " authentication = get_token_authentication(token)\n", "else:\n", " if QI_EMAIL is None or QI_PASSWORD is None:\n", " print('Enter email')\n", " email = input()\n", " print('Enter password')\n", " password = getpass()\n", " else:\n", " email, password = QI_EMAIL, QI_PASSWORD\n", " authentication = get_basic_authentication(email, password)\n", "\n", "qi_api = QuantumInspireAPI(QI_URL, authentication)\n", "\n", "projectq_backend = QIBackend(quantum_inspire_api=qi_api)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Execute algorithm on QX simulator" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We create an algorithm to entangle qubit 0 and qubit 4." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Measured 1,0,0,0,1\n", "Probabilities: {'00000': 0.5146484375, '10001': 0.4853515625}\n", "version 1.0\n", "# cQASM generated by Quantum Inspire class\n", "qubits 5\n", "\n", "h q[0]\n", "cnot q[0], q[4]\n" ] } ], "source": [ "engine = MainEngine(backend=projectq_backend) # create default compiler (simulator back-end)\n", "\n", "qubits = engine.allocate_qureg(5)\n", "q1 = qubits[0]\n", "q2 = qubits[-1]\n", "\n", "H | q1 # apply a Hadamard gate\n", "CNOT | (q1, q2)\n", "All(Measure) | qubits # measure the qubits\n", "\n", "engine.flush() # flush all gates (and execute measurements)\n", "\n", "print(\"Measured {}\".format(','.join([str(int(q)) for q in qubits])))\n", "print('Probabilities: %s' % (projectq_backend.get_probabilities(qubits),))\n", "print(projectq_backend.cqasm())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Simulate a spin-qubit array" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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.\n", "Our engine lists is generated by the `projectq.setups.linear` module." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Measured 1,0,0,0,1\n", "Probabilities: {'10001': 0.505859375, '00000': 0.494140625}\n", "version 1.0\n", "# cQASM generated by Quantum Inspire class\n", "qubits 5\n", "\n", "rx q[0],1.5707963268\n", "rz q[0],1.5707963268\n", "rx q[0],7.85398163397\n", "cnot q[0], q[1]\n" ] } ], "source": [ "projectq_backend = QIBackend(quantum_inspire_api=qi_api)\n", "engine_list = linear.get_engine_list(num_qubits=5, one_qubit_gates=(Rx, Rz), two_qubit_gates=(CNOT,))\n", "engine = MainEngine(backend=projectq_backend, engine_list=engine_list) # create default compiler (simulator back-end)\n", "\n", "qubits = engine.allocate_qureg(5)\n", "q1 = qubits[0]\n", "q2 = qubits[-1]\n", "\n", "H | q1 # apply a Hadamard gate\n", "CNOT | (q1, q2)\n", "All(Measure) | qubits # measure the qubits\n", "\n", "engine.flush() # flush all gates (and execute measurements)\n", "\n", "print(\"Measured {}\".format(','.join([str(int(q)) for q in qubits])))\n", "print('Probabilities: %s' % (projectq_backend.get_probabilities(qubits),))\n", "print(projectq_backend.cqasm())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "mapping logical qubit 0 to physical qubit 0\n", "mapping logical qubit 4 to physical qubit 1\n", "mapping logical qubit 1 to physical qubit 2\n", "mapping logical qubit 2 to physical qubit 3\n", "mapping logical qubit 3 to physical qubit 4\n" ] } ], "source": [ "current_mapping = engine.mapper.current_mapping\n", "for l, p in current_mapping.items():\n", " print('mapping logical qubit %d to physical qubit %d' % (l, p))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.8" }, "pycharm": { "stem_cell": { "cell_type": "raw", "metadata": { "collapsed": false }, "source": [] } } }, "nbformat": 4, "nbformat_minor": 2 }