{ "cells": [ { "cell_type": "markdown", "id": "26c21ec5", "metadata": {}, "source": [ "# Example for execution of multiple circuits in QPUs" ] }, { "cell_type": "markdown", "id": "df8dc942", "metadata": {}, "source": [ "Before executing, you must set up and `qraise` the QPUs, check the `README.md` for instructions. For this examples it will be optimal to have more than one QPU and at least one of them with ideal AerSimulator." ] }, { "cell_type": "markdown", "id": "86cdbafe", "metadata": {}, "source": [ "### Importing and adding paths to `sys.path`" ] }, { "cell_type": "code", "execution_count": 1, "id": "c532632a", "metadata": {}, "outputs": [], "source": [ "import os, sys\n", "\n", "# path to access c++ files\n", "sys.path.append(os.getenv(\"HOME\"))" ] }, { "cell_type": "markdown", "id": "368e94bf", "metadata": {}, "source": [ "### Let's get the QPUs that we q-raised!" ] }, { "cell_type": "code", "execution_count": 2, "id": "c2d0c54e", "metadata": { "scrolled": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "QPU 0, backend: SimpleSimulator, simulator: SimpleMunich, version: 0.0.1.\n", "QPU 1, backend: SimpleSimulator, simulator: SimpleMunich, version: 0.0.1.\n", "QPU 2, backend: SimpleSimulator, simulator: SimpleMunich, version: 0.0.1.\n" ] } ], "source": [ "from cunqa import getQPUs\n", "\n", "qpus = getQPUs(local=False)\n", "\n", "for q in qpus:\n", " print(f\"QPU {q.id}, backend: {q.backend.name}, simulator: {q.backend.simulator}, version: {q.backend.version}.\")\n" ] }, { "cell_type": "markdown", "id": "0b312b18", "metadata": {}, "source": [ "The method `getQPUs()` accesses the information of the raised QPus and instanciates one `qpu.QPU` object for each, returning a list. If you are working with `jupyter notebook` we recomend to instanciate this method just once.\n", "\n", "About the `qpu.QPU` objects:\n", "\n", "- `QPU.id`: identificator of the virtual QPU, they will be asigned from 0 to n-1.\n", "\n", "\n", "- `QPU.backend`: object `backend.Backend` that has information about the simulator and backend for the given QPU.\n" ] }, { "cell_type": "markdown", "id": "2ce62634", "metadata": {}, "source": [ "### Let's create a circuit to run in our QPUs!" ] }, { "cell_type": "markdown", "id": "29555d4b", "metadata": {}, "source": [ "We can create the circuit using `qiskit` or writting the instructions in the `json` format specific for `cunqa` (check the `README.md`), `OpenQASM2` is also supported. Here we choose not to complicate things and we create a `qiskit.QuantumCircuit`:" ] }, { "cell_type": "code", "execution_count": 3, "id": "c5350387", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
┌───┐┌──────┐┌───────┐ ░ ┌─┐ \n", " q_0: ┤ X ├┤0 ├┤0 ├─░─┤M├────────────\n", " └───┘│ ││ │ ░ └╥┘┌─┐ \n", " q_1: ─────┤1 ├┤1 ├─░──╫─┤M├─────────\n", " │ ││ │ ░ ║ └╥┘┌─┐ \n", " q_2: ─────┤2 QFT ├┤2 IQFT ├─░──╫──╫─┤M├──────\n", " ┌───┐│ ││ │ ░ ║ ║ └╥┘┌─┐ \n", " q_3: ┤ X ├┤3 ├┤3 ├─░──╫──╫──╫─┤M├───\n", " ├───┤│ ││ │ ░ ║ ║ ║ └╥┘┌─┐\n", " q_4: ┤ X ├┤4 ├┤4 ├─░──╫──╫──╫──╫─┤M├\n", " └───┘└──────┘└───────┘ ░ ║ ║ ║ ║ └╥┘\n", "meas: 5/══════════════════════════╩══╩══╩══╩══╩═\n", " 0 1 2 3 4" ], "text/plain": [ " ┌───┐┌──────┐┌───────┐ ░ ┌─┐ \n", " q_0: ┤ X ├┤0 ├┤0 ├─░─┤M├────────────\n", " └───┘│ ││ │ ░ └╥┘┌─┐ \n", " q_1: ─────┤1 ├┤1 ├─░──╫─┤M├─────────\n", " │ ││ │ ░ ║ └╥┘┌─┐ \n", " q_2: ─────┤2 QFT ├┤2 IQFT ├─░──╫──╫─┤M├──────\n", " ┌───┐│ ││ │ ░ ║ ║ └╥┘┌─┐ \n", " q_3: ┤ X ├┤3 ├┤3 ├─░──╫──╫──╫─┤M├───\n", " ├───┤│ ││ │ ░ ║ ║ ║ └╥┘┌─┐\n", " q_4: ┤ X ├┤4 ├┤4 ├─░──╫──╫──╫──╫─┤M├\n", " └───┘└──────┘└───────┘ ░ ║ ║ ║ ║ └╥┘\n", "meas: 5/══════════════════════════╩══╩══╩══╩══╩═\n", " 0 1 2 3 4 " ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from qiskit import QuantumCircuit\n", "from qiskit.circuit.library import QFT\n", "\n", "n = 5 # number of qubits\n", "\n", "qc = QuantumCircuit(n)\n", "\n", "qc.x(0); qc.x(n-1); qc.x(n-2)\n", "\n", "qc.append(QFT(n), range(n))\n", "\n", "qc.append(QFT(n).inverse(), range(n))\n", "\n", "qc.measure_all()\n", "\n", "display(qc.draw())" ] }, { "cell_type": "markdown", "id": "bf2f0f88", "metadata": {}, "source": [ "### Execution time! Let's do it sequentially" ] }, { "cell_type": "code", "execution_count": 4, "id": "c5c6682c", "metadata": { "scrolled": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "For QPU 0, with backend SimpleSimulator:\n", "Result: \n", "{'01001': 1000}\n", " Time taken: 0.00019069599511567503 s.\n", "For QPU 1, with backend SimpleSimulator:\n", "Result: \n", "{'01001': 1000}\n", " Time taken: 0.00019186599820386618 s.\n", "For QPU 2, with backend SimpleSimulator:\n", "Result: \n", "{'01001': 1000}\n", " Time taken: 0.0001888029946712777 s.\n" ] } ], "source": [ "counts = []\n", "\n", "for i, qpu in enumerate(qpus):\n", "\n", " print(f\"For QPU {qpu.id}, with backend {qpu.backend.name}:\")\n", " \n", " # 1)\n", " qjob = qpu.run(qc, transpile = True, shots = 1000)# non-blocking call\n", "\n", " # 2)\n", " result = qjob.result # bloking call\n", "\n", " # 3)\n", " time = qjob.time_taken\n", " counts.append(result.counts)\n", "\n", " print(f\"Result: \\n{result.counts}\\n Time taken: {time} s.\")" ] }, { "cell_type": "markdown", "id": "a0ed6a3b", "metadata": {}, "source": [ "1. First we run the circuit with the method `QPU.run()`, passing the circuit, transpilation options and other run parameters. It is important to note that if we don´t specify `transpilation=True`, default is `False`, therefore the user will be responsible for the tranpilation of the circuit accordingly to the native gates and topology of the backend. This method will return a `qjob.QJob` object. Be aware that the key point is that the `QPU.run()` method is **asynchronous**.\n", "\n", "\n", "2. To get the results of the simulation, we apply the method `QJob.result()`, which will return a `qjob.Result` object that stores the information in its class atributes. Depending on the simulator, we will have more or less information. Note that this is a **synchronous** method.\n", "\n", "\n", "3. Once we have the `qjob.Result` object, we can obtain the counts dictionary by `Result.get_counts()`. Another method independent from the simulator is `Result.time_taken()`, that gives us the time of the simulation in seconds." ] }, { "cell_type": "code", "execution_count": 5, "id": "94a4e3b4", "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "