{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Qiskit Tutorials\n", "\n", "Starting with Qiskit let's see how we can use the binders\n", "\n", "\n", "## QLM to Qiskit conversion\n", "\n", "We'll start with QLM to Qiskit conversion" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from qat.interop.qiskit import qlm_to_qiskit\n", "from qat.lang.AQASM import Program\n", "from qat.lang.AQASM.gates import H, CNOT\n", "\n", "nbqubits = 2\n", "\n", "prog = Program()\n", "\n", "qreg = prog.qalloc(nbqubits)\n", "creg = prog.calloc(nbqubits)\n", "\n", "prog.apply(H, qreg[0])\n", "prog.apply(CNOT, qreg[0], qreg[1])\n", "\n", "prog.measure(qreg, creg)\n", "qlm_circuit = prog.to_circ()\n", "\n", "# Conversion\n", "qiskit_circuit = qlm_to_qiskit(qlm_circuit)\n", "print(qiskit_circuit)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Qiskit to QLM conversion\n", "\n", "This conversion is going to be similar with every other language, the function `qiskit_to_qlm` is going to be the same for \n", "the other languages with two parameters: the circuit, and a boolean `sep_measure` if set to `True` it will return the qubits \n", "to measure separately for the user to measure them manually.\n", "A tuple of 2 elements is then returned, the first element is the circuit with no measures, the second one is a list containing the qubits to be measured.\n", "If set to `False` (which is the default value) only the QLM circuit will be returned (with measures included inside the circuit). " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from qat.interop.qiskit import qiskit_to_qlm\n", "from qiskit import QuantumRegister, QuantumCircuit, ClassicalRegister\n", "from qat.core.util import get_syntax\n", "\n", "nbqubits = 2\n", "\n", "qreg = QuantumRegister(nbqubits)\n", "creg = ClassicalRegister(nbqubits)\n", "\n", "qiskit_circuit = QuantumCircuit(qreg, creg)\n", "\n", "qiskit_circuit.h(qreg[0])\n", "qiskit_circuit.cx(qreg[0], qreg[1])\n", "qiskit_circuit.measure(qreg, creg)\n", "\n", "# get result with included measures\n", "qlm_circuit = qiskit_to_qlm(qiskit_circuit)\n", "\n", "for index, op in enumerate(qlm_circuit.ops):\n", " print(\"Gate {} with params {} on qubits {} and cbits {}\".format(*get_syntax(qlm_circuit, index), op.cbits))\n", "\n", "# get result with separated measures\n", "print(\"---------------------------------------------------------\")\n", "qlm_circuit, to_measure = qiskit_to_qlm(qiskit_circuit, sep_measures=True)\n", "\n", "for index, op in enumerate(qlm_circuit.ops):\n", " print(\"Gate {} with params {} on qubits {}\".format(*get_syntax(qlm_circuit, index)))\n", "print(\"qubits to measure {}\".format(to_measure))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## BackendToQPU\n", "\n", "A wrapper implementing `QPUHandler` in order to run _synchronous_ QLM circuits in qiskit backends seamlessly and without any hassle" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from qat.interop.qiskit import BackendToQPU\n", "from qiskit import Aer\n", "from qat.lang.AQASM import Program\n", "from qat.lang.AQASM.gates import *\n", "\n", "nbqubits = 2\n", "\n", "prog = Program()\n", "\n", "qreg = prog.qalloc(nbqubits)\n", "creg = prog.calloc(nbqubits)\n", "\n", "prog.apply(H, qreg[0])\n", "prog.apply(CNOT, qreg[0], qreg[1])\n", "\n", "prog.measure(qreg, creg)\n", "qlm_circuit = prog.to_circ()\n", "\n", "qlm_job = qlm_circuit.to_job(nbshots=1024)\n", "\n", "# Building a default BackendToQPU that's going to use qiskit's \"qasm_simulator\" if it couldn't connect\n", "# to IBMQ using a token\n", "qpu = BackendToQPU()\n", "\n", "\n", "result = qpu.submit(qlm_job)\n", "for entry in result.raw_data:\n", " print(\"State: {}\\t probability: {}\".format(entry.state, entry.probability))\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## AsyncBackendToQPU\n", "\n", "We can also have the same thing but this time with an asynchronous qiskit qpu, this won't have the same interface as Qiskit,\n", "but it will have the same interface as our QLM `Asyncjob`" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "from qat.interop.qiskit import AsyncBackendToQPU\n", "from qiskit import Aer\n", "from qat.lang.AQASM import Program\n", "from qat.lang.AQASM.gates import *\n", "import time\n", "nbqubits = 2\n", "\n", "prog = Program()\n", "\n", "qreg = prog.qalloc(nbqubits)\n", "creg = prog.calloc(nbqubits)\n", "\n", "prog.apply(H, qreg[0])\n", "prog.apply(CNOT, qreg[0], qreg[1])\n", "\n", "prog.measure(qreg, creg)\n", "qlm_circuit = prog.to_circ()\n", "\n", "qlm_job = qlm_circuit.to_job(nbshots=1024)\n", "\n", "# Building a default AsyncBackendToQPU that's going to use qiskit's \"qasm_simulator\" if it couldn't connect\n", "# to IBMQ using a token\n", "qpu = AsyncBackendToQPU()\n", "\n", "async_job = qpu.submit(qlm_job)\n", "\n", "print(\"ID: {}\\t status : {}\".format(async_job.job_id(), async_job.status()))\n", "time.sleep(0.01)\n", "print(\"ID: {}\\t status : {}\".format(async_job.job_id(), async_job.status()))\n", "time.sleep(0.2)\n", "print(\"ID: {}\\t status : {}\".format(async_job.job_id(), async_job.status()))\n", "while async_job.result() is None:\n", " time.sleep(5)\n", "result = async_job.result()\n", "for entry in result.raw_data:\n", " print(\"State: {}\\t probability: {}\".format(entry.state, entry.probability))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## QPUToBackend\n", "\n", "We have implemented a qiskit style backend, that can be plugged seamlessly into qiskit's ecosystem. With this you can simulate qiskit circuits with any simulator you want that's available in the QLM (this of course includes other simulators like pyquil)." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": false }, "outputs": [], "source": [ "from qat.interop.qiskit import QPUToBackend\n", "from qat.qpus import PyLinalg\n", "from qiskit import QuantumRegister, QuantumCircuit, ClassicalRegister, execute, Aer\n", "from qat.comm.shared.ttypes import Batch\n", "nbqubits = 2\n", "\n", "qreg = QuantumRegister(nbqubits)\n", "creg = ClassicalRegister(nbqubits)\n", "\n", "qiskit_circuit = QuantumCircuit(qreg, creg)\n", "\n", "qiskit_circuit.h(qreg[0])\n", "qiskit_circuit.cx(qreg[0], qreg[1])\n", "qiskit_circuit.measure(qreg, creg)\n", "\n", "\n", "qpu = PyLinalg()\n", "backend = QPUToBackend(qpu)\n", "\n", "result = execute(qiskit_circuit, backend, shots=15).result()\n", "\n", "print(result.results)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## QVM installation and execution\n", "\n", "You have to install forest sdk following [these](http://docs.rigetti.com/en/stable/start.html#start) steps.\n", "\n", "Then after installation you might need to also download `libblas.so` and `liblapack.so` from the internet,\n", "\n", "afterwards you can run the server using this command :" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "!export QVM_PATH=/my/path/forest-sdk_2.7.0-linux-barebones/; LD_LIBRARY_PATH=$QVM_PATH $QVM_PATH/qvm -S --skip-version-check -p 17701" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## QLMBackend using Pyquil Simulator\n", "\n", "Let us put what we hypothesized earlier to the test, this time instead of using a native QLM simulator, we will use `PyquilQPU` the qpu wrapper around pyquil's qvm. `QiskitConnector` is an object that is used in the same way as a QLM plugin, and yields a QPUToBackend object when given a QPU.
\n", "**Warning:** While the example below is relevent to see how `QiskitConnector` works, it will only yield an error in this specific case if the command above was not used to run a qvm server.\n", "\n", "**Warning:** The below cell will not work for python 3.6, the pyquil binder is deprecated for this version." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "import sys\n", "\n", "if sys.version_info >= (3, 7):\n", "\n", " import os\n", " from qat.interop.qiskit import QiskitConnector\n", " from qat.interop.pyquil.providers import PyquilQPU\n", " from qiskit import QuantumRegister, QuantumCircuit, ClassicalRegister, execute\n", " from pyquil import get_qc\n", " nbqubits = 2\n", " qreg = QuantumRegister(nbqubits)\n", " creg = ClassicalRegister(nbqubits)\n", "\n", " qiskit_circuit = QuantumCircuit(qreg, creg)\n", "\n", " qiskit_circuit.h(qreg[0])\n", " qiskit_circuit.cx(qreg[0], qreg[1])\n", " qiskit_circuit.measure(qreg, creg)\n", "\n", " # Connection to the qvm running as server\n", " os.environ[\"QCS_SETTINGS_APPLICATIONS_PYQUIL_QVM_URL\"] = \"http://127.0.0.1:17701\"\n", " os.environ[\"QCS_SETTINGS_APPLICATIONS_PYQUIL_QUILC_URL\"] = \"tcp://127.0.0.1:17702\"\n", " qvm = get_qc('9q-qvm')\n", "\n", " # Building the backend while using qiskit backend as a plugin\n", " backend = QiskitConnector() | PyquilQPU(qvm)\n", "\n", " # This result is in qiskit form since it was executed on qiskit\n", " result = execute(qiskit_circuit, backend, shots=1024).result()\n", "\n", " print(result.results)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Abstract variables\n", "\n", "Conversion of circuits containing abstract variables is supported between Qiskit and QLM. It is done in the same way as other circuits." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# QLM to Qiskit\n", "prog = Program()\n", "qbits = prog.qalloc(2)\n", "theta = prog.new_var(float, \"theta\")\n", "gamma = 3.14 - 2 * theta\n", "prog.apply(RX(theta), qbits[0])\n", "prog.apply(RX(gamma), qbits[1])\n", "\n", "qlm_circuit = prog.to_circ()\n", "qiskit_circuit = qlm_to_qiskit(qlm_circuit)\n", "print(qiskit_circuit)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from qiskit.circuit import Parameter\n", "\n", "# Qiskit to QLM\n", "qiskit_circuit = QuantumCircuit(2)\n", "theta = Parameter(\"theta\")\n", "gamma = 3.14 - 2 * theta\n", "qiskit_circuit.rx(theta, 0)\n", "qiskit_circuit.rx(gamma, 1)\n", "\n", "qlm_circuit = qiskit_to_qlm(qiskit_circuit)\n", "qlm_circuit.display()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "authors": [ "Simon Martiel", "Arnaud Gazda" ], "constraints": { "have_second_server": "17702", "have_server": "17701" }, "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.12.11" } }, "nbformat": 4, "nbformat_minor": 2 }