diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ad2e38a..da3116a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,11 +9,6 @@ repos: - id: trailing-whitespace - id: mixed-line-ending - - repo: https://github.com/codespell-project/codespell - rev: v2.3.0 - hooks: - - id: codespell - - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.6.9 hooks: diff --git a/docs/calibration.md b/docs/calibration.md index 71b181d..a84a7f0 100644 --- a/docs/calibration.md +++ b/docs/calibration.md @@ -1,27 +1,20 @@ Helmi is continuously calibrated to ensure functionality. The calibration process involves a series of experiments, aimed at fine-tuning the parameters, necessary for controlling and measuring the qubits. In addition to calibration, we run benchmarks to obtain the figures of merit reflecting the current state of the quantum computer. -!!! note - - Calibration and benchmarking experiments are interleaved with regular user jobs in Helmi's job queue, as detailed in the [Running on Helmi](running.md) section. The calibration might therefore slightly increase the waiting time in the queue of regular user jobs. - ### Calibration sequences -To minimize the impact of calibration on user operations, we execute shorter calibration sequences during the day and a longer calibration run throughout the night. - -**Short calibration**: +To minimize the impact of calibration on user operations, we schedule the calibration of Helmi at 2AM, by running a specific sequence of experiments in order. Calibration and benchmarking experiments are interleaved with regular user jobs in Helmi's job queue, as detailed in the [Running on Helmi](running.md) section. The calibration might therefore slightly increase the waiting time in the queue of regular user jobs. -- Every 2 hours from 11 am to 11 pm -- Adjusts qubit drive frequency, drive amplitude and readout threshold -- Measures $T_1$, $T_2$, $T_2^*$ and readout accuracy +**Calibration**: -**Extended calibration**: - -- Every day at 4 am +- Every day at 2 am - Adjusts qubit drive frequency, amplitude fine-tuning and readout threshold +- Recalibrates CZ Gate, Virtual Z rotations and performs randomized benchmarking. - Measures $T_1$, $T_2$, $T_2^*$, readout accuracy, single- and two-qubit gate fidelities A calibration sequence produces what is called a `calibration_set`. This is a set of device parameters, which the quantum computer is currently using to execute quantum circuits. It is identified via a `calibration_set_id`, a unique identifier for the specific `calibration_set`. Usually, when submitting quantum circuits, the most up-to-date calibration set is used, however, it is possible to use a specific `calibration_set_id`. This can be useful for testing the degradation of the performance of our quantum computers. +The `calibration set` sometimes contains observations with the suffix `par=d2`. This refers to the distance of the qubit pairs that can run in parallel, which is necessary to avoid neighbouring qubit pairs of the same group. + ### Quality metrics set The benchmarks results are summarized in the *quality metric set* representing the figures of merit and reflecting the latest state of the quantum computer. The calibration metrics can be fetched from Helmi's API by sending HTTP `GET` requests to `/calibration/metrics/latest`. An example script is provided [here](https://github.com/FiQCI/helmi-examples/blob/main/scripts/get_calibration_data.py). Each quality metrics set is identified via a unique ID, with a new ID created after each calibration. Note, that not all metrics are updated after each calibration run. We recommend to save the current calibration set ID together with the job ID to facilitate debugging and analysis. Also note that it can happen that there is a delay of up to 10 minutes between calibrating the device and benchmarking the quality metrics set, causing there to be some delay in presenting the quality metrics data. @@ -49,21 +42,44 @@ Here is an example response from Helmi's API for the calibration and quality met ```json { - "calibration_set_id": "03436204-3588-4567-95ec-5a61acfd227d", - "quality_metric_set_id": "ec1298a0-43ce-43f2-b6d1-10c1fe750786", - "metrics": { - "QB1.fidelity_1qb_gates_averaged": { - "value": "0.9971526901996984", - "unit": "", - "uncertainty": "5.622242981254397e-05", - "timestamp": "2024-03-20T05:05:08.109836" + 'calibration_set_id': '15c05aaf-e1d4-4020-85b4-c3f234c41b7b', + 'calibration_set_dut_label': 'M127_W49_A02_J11', + 'calibration_set_number_of_observations': 166, + 'calibration_set_created_timestamp': '2024-11-29 02:55:42.607368+00:00', + 'calibration_set_end_timestamp': '2024-11-29 02:55:42.771789+00:00', + 'calibration_set_is_invalid': False, + 'quality_metric_set_id': '8ce54091-78d9-4823-ae67-7a65b407c221', + 'quality_metric_set_dut_label': 'M127_W49_A02_J11', + 'quality_metric_set_created_timestamp': '2024-11-29 02:55:42.740569+00:00', + 'quality_metric_set_end_timestamp': '2024-11-29 02:55:42.797275+00:00', + 'quality_metric_set_is_invalid': False, + 'metrics': + { + 'measure_ssro_fidelity': + { + 'QB1': + { + 'value': '0.949', + 'unit': '', + 'uncertainty': 'None', + 'timestamp': '2024-11-29 04:55:42.648725+00:00', + 'implementation': 'constant' + }, + 'QB2': + { + 'value': '0.9427499999999999', + 'unit': '', + 'uncertainty': 'None', + 'timestamp': '2024-11-29 04:55:42.648725+00:00', + 'implementation': 'constant' }, - "TC-3-5.cz_gate_fidelity": { - "value": "0.9848983187049354", - "unit": "", - "uncertainty": "0.002603321013490276", - "timestamp": "2024-03-20T05:05:08.109836" + 'QB3': + { + 'value': '0.95125', + 'unit': '', + 'uncertainty': 'None', + 'timestamp': '2024-11-29 04:55:42.648725+00:00', + 'implementation': 'constant' } - } -} +... ``` diff --git a/docs/examples/intro-to-helmi-cirq.ipynb b/docs/examples/intro-to-helmi-cirq.ipynb index a75b4cd..dca9b64 100644 --- a/docs/examples/intro-to-helmi-cirq.ipynb +++ b/docs/examples/intro-to-helmi-cirq.ipynb @@ -31,8 +31,9 @@ "This notebook uses the following requirements. \n", "\n", "```text\n", - "cirq-iqm==14.0\n", - "iqm-client==17.5\n", + "cirq-iqm==15.1\n", + "iqm-client==20.5\n", + "networkx\n", "```" ] }, @@ -42,7 +43,7 @@ "source": [ "## Using Helmi with Cirq\n", "\n", - "First we import [cirq-on-iqm](https://github.com/iqm-finland/cirq-on-iqm) which is needed to run on Helmi with cirq. You can read the user guide [here](https://iqm-finland.github.io/cirq-on-iqm/versions/11.9/user_guide.html)." + "First we import [cirq-on-iqm](https://github.com/iqm-finland/cirq-on-iqm) which is needed to run on Helmi with cirq. You can read the user guide [here](https://iqm-finland.github.io/cirq-on-iqm/user_guide.html)." ] }, { @@ -73,7 +74,17 @@ "metadata": {}, "outputs": [], "source": [ - "sampler = IQMSampler(\"https://qc.vtt.fi/helmi/cocos\")\n", + "import os\n", + "\n", + "sampler = IQMSampler(os.environ[\"HELMI_CORTEX_URL\"])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ "device = sampler.device" ] }, @@ -90,11 +101,14 @@ "metadata": {}, "outputs": [], "source": [ + "from iqm.iqm_client import CircuitCompilationOptions, HeraldingMode\n", + "\n", "sampler = IQMSampler(\n", - " \"https://qc.vtt.fi/helmi/cocos\",\n", - " calibration_set_id=\"2318283e-3adf-4a88-a936-a33affde4af7\",\n", - " max_circuit_duration_over_t2=1.0,\n", - " heralding_mode=\"zeros\",\n", + " os.environ[\"HELMI_CORTEX_URL\"],\n", + " calibration_set_id=\"e0cf7953-1eb8-4c71-a262-301380baa2c4\",\n", + " compiler_options=CircuitCompilationOptions(\n", + " max_circuit_duration_over_t2=None, heralding_mode=HeraldingMode.ZEROS\n", + " ),\n", ")" ] }, @@ -361,14 +375,14 @@ "- [Long-distance transmon coupler with CZ gate fidelity above 99.8%](https://arxiv.org/pdf/2208.09460.pdf). Paper by IQM describing the superconducting technology behind Helmi. \n", "- [Helmi press release](https://www.vttresearch.com/en/news-and-ideas/finlands-first-5-qubit-quantum-computer-now-operational). \n", "- [cirq-on-iqm Github page](https://github.com/iqm-finland/cirq-on-iqm).\n", - "- [cirq-on-iqm documentation](https://iqm-finland.github.io/cirq-on-iqm/). We are running `11.13`.\n", + "- [cirq-on-iqm documentation](https://iqm-finland.github.io/cirq-on-iqm/). We are running `15.2`.\n", "- [CSC documentation on Helmi](https://docs.csc.fi/computing/quantum-computing/overview/)." ] } ], "metadata": { "kernelspec": { - "display_name": "qas2023", + "display_name": "qc-docs", "language": "python", "name": "python3" }, @@ -382,7 +396,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.10" + "version": "3.11.10" }, "orig_nbformat": 4 }, diff --git a/docs/examples/intro-to-helmi-qiskit.ipynb b/docs/examples/intro-to-helmi-qiskit.ipynb index a1f0862..4cc9404 100644 --- a/docs/examples/intro-to-helmi-qiskit.ipynb +++ b/docs/examples/intro-to-helmi-qiskit.ipynb @@ -31,10 +31,11 @@ "This notebook uses the following requirements. \n", "\n", "```text\n", - "qiskit-iqm==13.7\n", - "iqm-client==17.5\n", + "qiskit-iqm==15.4\n", + "iqm-client==20.5\n", "qiskit[visualization]\n", "pylatexenc\n", + "networkx\n", "```" ] }, @@ -53,11 +54,12 @@ "metadata": {}, "outputs": [], "source": [ + "import os\n", + "\n", "import networkx as nx\n", "from iqm.qiskit_iqm import IQMProvider\n", "from iqm.qiskit_iqm.iqm_transpilation import optimize_single_qubit_gates\n", - "from qiskit import QuantumCircuit, QuantumRegister, execute, transpile\n", - "from qiskit.tools.monitor import job_monitor\n", + "from qiskit import QuantumCircuit, QuantumRegister, transpile\n", "from qiskit.visualization import plot_histogram" ] }, @@ -65,7 +67,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Then connection to the backend is simple! For this we point the `IQMProvider` at what is called the \"cocos URL\". The cocos url to access Helmi is provided below. " + "Then connection to the backend is simple! For this we point the `IQMProvider` at Helmi URL. The Helmi URL is present in the environment variable and should be loaded as provided below. " ] }, { @@ -74,7 +76,7 @@ "metadata": {}, "outputs": [], "source": [ - "provider = IQMProvider(\"https://qc.vtt.fi/helmi/cocos\")\n", + "provider = IQMProvider(os.environ[\"HELMI_CORTEX_URL\"])\n", "backend = provider.get_backend()" ] }, @@ -121,7 +123,7 @@ "source": [ "### Constructing and executing quantum circuits\n", "\n", - "Circuits are constructed and submitted to Helmi using the same methods as with IBM machines. First we construct a Bell pair circuit between 2 qubits. The circuit is then executed on the backend using the `execute` function. " + "Circuits are constructed and submitted to Helmi using the same methods as with IBM machines. First we construct a Bell pair circuit between 2 qubits. The circuit is then executed on the backend using the `backend.run` function. " ] }, { @@ -142,8 +144,7 @@ "metadata": {}, "source": [ "### Executing the circuit on Helmi\n", - "\n", - "When submitting a job to Helmi a unique identifier for your job is returned. This can be used to gather additional information about the circuit you just submitted and the results. **You should save your job ids!**" + "We now transpile the circuit to run on Helmi. This will rewrite the circuit to take into account Helmi's topology and native gate set. We can also view the transpiled circuit before running it:" ] }, { @@ -152,17 +153,15 @@ "metadata": {}, "outputs": [], "source": [ - "job = execute(circuit, backend, shots=100)\n", - "print(f\"Job ID: {job.job_id()}.\")\n", - "print(\"Tracking execution of job:\")\n", - "job_monitor(job)" + "transpiled_circuit = transpile(circuit, backend)\n", + "transpiled_circuit.draw(output=\"mpl\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "The `execute` function from qiskit performs the quantum circuit transpilation by default. If you want to inspect the transpiled circuit, the `circuit_callback` option can be used. To run without automatic transpilation, `backend.run` can be used directly, in which case transpilation must be performed manually. " + "We can now submit the job to run. When submitting a job to Helmi a unique identifier for your job is returned. This can be used to gather additional information about the circuit you just submitted and the results. **You should save your job ids!**" ] }, { @@ -171,15 +170,18 @@ "metadata": {}, "outputs": [], "source": [ - "def print_circ(circuit):\n", - " for qc in circuit:\n", - " print(qc.draw())\n", - "\n", - "\n", - "job = execute(circuit, backend, shots=100, circuit_callback=print_circ)\n", - "print(f\"Job ID: {job.job_id()}.\")\n", - "print(\"Tracking execution of job:\")\n", - "job_monitor(job)" + "backend.set_options(shots=100)\n", + "job = backend.run(transpiled_circuit)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "job = backend.run(transpiled_circuit)\n", + "print(f\"Job ID: {job.job_id()}.\")" ] }, { @@ -209,31 +211,21 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "You can also specify some backend arguments for running on Helmi. These are explained in the [qiskit-on-iqm documentation](https://iqm-finland.github.io/qiskit-on-iqm/user_guide.html#installation)." + "You can also specify some backend arguments for running on Helmi. These are explained in the [qiskit-on-iqm documentation](https://iqm-finland.github.io/qiskit-on-iqm/user_guide.html#executing-a-circuit)." ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "# job = execute(\n", - "# circuit,\n", - "# backend,\n", - "# shots=100,\n", - "# calibration_set_id=\"c5a5e2d1-100b-42d4-a4fd-a49edfb9d176\",\n", - "# max_circuit_duration_over_t2=1.0,\n", - "# heralding_mode=\"zeros\",\n", - "# circuit_callback=None,\n", - "# )" + "The IQM backend always corresponds to a `calibration set`, so that transpiling using this backend will only use loci defined in the `calibration_set_id`. The server default calibration set will be used unless one is provided while instantiating the backend." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "After submitting, the job is now running. The status of the job can be queried using `job.status()`. Using the job id, you can retrieve previous jobs. " + "The Various Circuit Compilation options that can be set while running a circuit can be found here [iqm-client documentation](https://iqm-finland.github.io/iqm-client/api/iqm.iqm_client.models.CircuitCompilationOptions.html)" ] }, { @@ -242,23 +234,45 @@ "metadata": {}, "outputs": [], "source": [ - "status = job.status()\n", - "print(status)\n", - "# old_job = backend.retrieve_job(job_id)" + "from iqm.iqm_client import CircuitCompilationOptions\n", + "from iqm.iqm_client.models import HeraldingMode\n", + "\n", + "backend = provider.get_backend(calibration_set_id=\"35fa13d1-17db-4bd2-9b14-203ce32f0551\")\n", + "\n", + "transpiled_circuit = transpile(circuit, backend)\n", + "transpiled_circuit.draw(\"mpl\")\n", + "\n", + "job2 = backend.run(\n", + " transpiled_circuit,\n", + " shots=1000,\n", + " circuit_compilation_options=CircuitCompilationOptions(\n", + " max_circuit_duration_over_t2=None, heralding_mode=HeraldingMode.ZEROS\n", + " ),\n", + ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### Explicit Transpilation" + "After submitting, the job is now running. The status of the job can be queried using `job.status()`. Using the job id, you can retrieve previous jobs. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(job2.job_id())\n", + "plot_histogram(job2.result().get_counts())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Instead of using the `execute` function you can also be explicit about your transpilation. " + "Additional metadata about the executed job can also be found." ] }, { @@ -267,17 +281,30 @@ "metadata": {}, "outputs": [], "source": [ - "transpiled_circuit = transpile(\n", - " circuit, backend=backend, layout_method=\"sabre\", optimization_level=3\n", - ")\n", - "transpiled_circuit.draw(\"mpl\")" + "result = job.result()\n", + "exp_result = result._get_experiment(transpiled_circuit)\n", + "print(\"Job ID: \", job.job_id()) # Retrieving the submitted job id\n", + "print(result.request.circuits) # Retrieving the circuit request sent\n", + "print(\n", + " \"Calibration Set ID: \", exp_result.calibration_set_id\n", + ") # Retrieving the current calibration set id.\n", + "print(result.request.qubit_mapping) # Retrieving the qubit mapping\n", + "print(result.request.shots) # Retrieving the number of requested shots.\n", + "print(exp_result.header)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Explicit Transpilation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "For more control, you can also specify the initial layout in both `transpile` and `execute`. For example, Helmi's topology only allows 2 qubit gates between the central and outer qubits. Therefore we can map the 2 qubit gate to QB3. For this we make use of the `QuantumRegister`. " + "For more control, you can also specify the initial layout in the `transpile` function. For example, Helmi's topology only allows 2 qubit gates between the central and outer qubits. Therefore we can map the 2 qubit gate to QB3. For this we make use of the `QuantumRegister`. " ] }, { @@ -292,15 +319,14 @@ "circuit.cx(qreg[0], qreg[1])\n", "circuit.measure_all()\n", "\n", - "\n", "# Qubit numbers start at 0 index whereas the qubit names start at 1 index.\n", "qubit_mapping = {\n", - " qreg[0]: 1, # Map the first qubit to QB1\n", - " qreg[1]: 2, # Map the second qubit to QB3\n", + " qreg[0]: backend.qubit_name_to_index(\"QB1\"),\n", + " qreg[1]: backend.qubit_name_to_index(\"QB2\"),\n", "}\n", "\n", - "\n", - "job = execute(circuit, backend, shots=100, initial_layout=qubit_mapping)" + "transpiled_circuit = transpile(circuit, backend, initial_layout=qubit_mapping)\n", + "job = backend.run(transpiled_circuit)" ] }, { @@ -345,53 +371,6 @@ "circuit_optimized.draw(\"mpl\")" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Results\n", - "\n", - "Results can be printed once the job has completed. If results are queried before the job has completed then an error will be returned. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "result = job.result()\n", - "print(result.job_id) # The job id can be queried from the result\n", - "print(result.get_counts())\n", - "# print(result.get_memory())\n", - "\n", - "plot_histogram(result.get_counts())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Additional metadata about the executed job can also be found." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "exp_result = result._get_experiment(circuit)\n", - "print(\"Job ID: \", job.job_id()) # Retrieving the submitted job id\n", - "print(result.request.circuits) # Retrieving the circuit request sent\n", - "print(\n", - " \"Calibration Set ID: \", exp_result.calibration_set_id\n", - ") # Retrieving the current calibration set id.\n", - "print(result.request.qubit_mapping) # Retrieving the qubit mapping\n", - "print(result.request.shots) # Retrieving the number of requested shots.\n", - "print(exp_result.header)" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -410,7 +389,8 @@ "from iqm.qiskit_iqm import IQMFakeAdonis\n", "\n", "fake_backend = IQMFakeAdonis()\n", - "job = execute(circuit, fake_backend, shots=1000)\n", + "transpiled_job = transpile(circuit, fake_backend)\n", + "job = fake_backend.run(circuit, shots=1000)\n", "print(job.result().get_counts())\n", "plot_histogram(job.result().get_counts())" ] @@ -487,7 +467,8 @@ "metadata": {}, "outputs": [], "source": [ - "job = execute(circuit, helmi_fake_backend, shots=1000)\n", + "transpiled_job = transpile(circuit, helmi_fake_backend)\n", + "job = helmi_fake_backend.run(circuit, shots=1000)\n", "print(job.result().get_counts())\n", "plot_histogram(job.result().get_counts())" ] @@ -517,7 +498,8 @@ "circuit_1.h(0)\n", "circuit_1.cx(0, 1)\n", "circuit_1.measure_all()\n", - "circuits_list.append(circuit_1)\n", + "transpiled_c1 = transpile(circuit_1, backend)\n", + "circuits_list.append(transpiled_c1)\n", "\n", "circuit_1.draw(output=\"mpl\")" ] @@ -532,7 +514,8 @@ "circuit_2.h(1)\n", "circuit_2.cx(1, 0)\n", "circuit_2.measure_all()\n", - "circuits_list.append(circuit_2)\n", + "transpiled_c2 = transpile(circuit_2, backend)\n", + "circuits_list.append(transpiled_c2)\n", "\n", "circuit_2.draw(output=\"mpl\")" ] @@ -544,19 +527,9 @@ "outputs": [], "source": [ "# Execute and monitor job\n", - "job = execute(\n", - " circuits_list, backend, shots=10, optimization_level=3, initial_layout=[0, 2]\n", + "job = helmi_fake_backend.run(\n", + " circuits_list, shots=1000, optimization_level=3, initial_layout=[0, 2]\n", ")\n", - "print(\"Tracking execution of job:\")\n", - "job_monitor(job)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ "# Get results\n", "result = job.result()\n", "\n", @@ -564,49 +537,13 @@ "plot_histogram(result.get_counts(), legend=[\"Circuit 1\", \"Circuit 2\"])" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## [Pennylane Qiskit](https://docs.pennylane.ai/projects/qiskit/en/latest/)\n", - "\n", - "You can also run Pennylane code on Helmi with the [PennyLane-Qiskit Plugin](https://docs.pennylane.ai/projects/qiskit/en/latest/). The `IQMBackend` object uses `BackendV2` currently which Pennylane-Qiskit does not support, therefore we use a [forked-version](https://github.com/NordIQuEst/pennylane-qiskit) that fixes this. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import pennylane as qml\n", - "\n", - "# provider = IQMProvider(\"https://qc.vtt.fi/helmi/cocos\")\n", - "# backend = provider.get_backend()\n", - "\n", - "\n", - "dev = qml.device(\"qiskit.remote\", wires=5, backend=backend, shots=10)\n", - "\n", - "print(dev.capabilities())\n", - "\n", - "\n", - "@qml.qnode(dev, interface=\"autograd\")\n", - "def circuit(params):\n", - " qml.RX(params[0], wires=0)\n", - " qml.RY(params[1], wires=0)\n", - " return qml.expval(qml.PauliZ(0))\n", - "\n", - "\n", - "print(circuit([0.54, 0.12]))" - ] - }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Summary\n", "\n", - "In this notebook we have demonstrated how to connect and run circuits on Helmi with Qiskit, qiskit-on-iqm and the PennyLane-Qiskit plugin. " + "In this notebook we have demonstrated how to connect and run circuits on Helmi with Qiskit and qiskit-on-iqm." ] }, { @@ -619,14 +556,13 @@ "- [Helmi press release](https://www.vttresearch.com/en/news-and-ideas/finlands-first-5-qubit-quantum-computer-now-operational). \n", "- [qiskit-on-iqm Github page](https://github.com/iqm-finland/qiskit-on-iqm).\n", "- [qiskit-on-iqm documentation](https://iqm-finland.github.io/qiskit-on-iqm/).\n", - "- [CSC documentation on Helmi](https://docs.csc.fi/computing/quantum-computing/overview/).\n", - "- [Pennylane-Qiskit documentation](https://docs.pennylane.ai/projects/qiskit/en/latest/)." + "- [CSC documentation on Helmi](https://docs.csc.fi/computing/quantum-computing/overview/)." ] } ], "metadata": { "kernelspec": { - "display_name": "qas2023", + "display_name": "qc-docs", "language": "python", "name": "python3" }, @@ -640,7 +576,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.10" + "version": "3.11.10" }, "orig_nbformat": 4 }, diff --git a/docs/examples/visualize_quality_metrics.ipynb b/docs/examples/visualize-quality-metrics.ipynb similarity index 90% rename from docs/examples/visualize_quality_metrics.ipynb rename to docs/examples/visualize-quality-metrics.ipynb index f70af72..8ff574a 100644 --- a/docs/examples/visualize_quality_metrics.ipynb +++ b/docs/examples/visualize-quality-metrics.ipynb @@ -61,13 +61,15 @@ " Optionally save the response to a json file, if filename is provided\n", " \"\"\"\n", " headers = {\"User-Agent\": client._signature}\n", - " bearer_token = client._get_bearer_token()\n", + " bearer_token = client._token_manager.get_bearer_token()\n", " headers[\"Authorization\"] = bearer_token\n", "\n", " if calibration_set_id:\n", - " url = os.path.join(client._base_url, \"calibration/metrics/\", calibration_set_id)\n", + " url = os.path.join(\n", + " client._api.iqm_server_url, \"calibration/metrics/\", calibration_set_id\n", + " )\n", " else:\n", - " url = os.path.join(client._base_url, \"calibration/metrics/latest\")\n", + " url = os.path.join(client._api.iqm_server_url, \"calibration/metrics/latest\")\n", "\n", " response = requests.get(url, headers=headers)\n", " response.raise_for_status() # will raise an HTTPError if the response was not ok\n", @@ -98,11 +100,8 @@ "metadata": {}, "outputs": [], "source": [ - "provider = IQMProvider(\"https://qc.vtt.fi/helmi/cocos\")\n", - "backend = provider.get_backend()\n", - "\n", - "# If you receive an error you may need to set the IQM_TOKENS_FILE environment variable\n", - "# os.environ[\"IQM_TOKENS_FILE\"] = \"/path/to/file\"" + "provider = IQMProvider(os.environ[\"HELMI_CORTEX_URL\"])\n", + "backend = provider.get_backend()" ] }, { @@ -167,12 +166,16 @@ "\n", "```json\n", "{\n", - " 'component.metric':\n", + " 'metric':\n", " {\n", - " 'value': '1',\n", - " 'unit': '',\n", - " 'uncertainity': '',\n", - " 'timestamp': '2024-04-08T05:05:47.58068'\n", + " 'component':\n", + " {\n", + " 'value': '1',\n", + " 'unit': '',\n", + " 'uncertainity': '',\n", + " 'timestamp': '2024-04-08T05:05:47.58068',\n", + " 'implementation': ''\n", + " }\n", " }\n", "}\n", "```" @@ -203,9 +206,11 @@ " # Iterate over the calibration data and collect values and labels based on the metric\n", " for key, metric_data in data[\"metrics\"].items():\n", " if key.endswith(metric):\n", - " values.append(float(metric_data[\"value\"]))\n", - " # Extract the qubit label from the key\n", - " labels.append(key.split(\".\")[0])\n", + " for qb, qb_data in metric_data.items():\n", + " if qb.startswith(\"QB\"):\n", + " values.append(float(qb_data[\"value\"]))\n", + " # Extract the qubit label from the key\n", + " labels.append(qb)\n", "\n", " # Check if values were found for the given metric\n", " if not values:\n", @@ -251,7 +256,7 @@ "outputs": [], "source": [ "plot_metrics(\n", - " metric=\"single_shot_readout_fidelity\",\n", + " metric=\"measure_ssro_fidelity\",\n", " title=\"Single Shot Readout Fidelities\",\n", " xlabel=\"Qubits\",\n", " ylabel=\"Success rate\",\n", @@ -346,7 +351,7 @@ "outputs": [], "source": [ "plot_metrics(\n", - " metric=\"fidelity_1qb_gates_averaged\",\n", + " metric=\"prx_rb_fidelity\",\n", " title=\"Single-qubit Gate Fidelities\",\n", " xlabel=\"Qubits\",\n", " ylabel=\"Fidelities\",\n", @@ -377,7 +382,7 @@ "outputs": [], "source": [ "plot_metrics(\n", - " metric=\"cz_gate_fidelity\",\n", + " metric=\"cz_irb_fidelity\",\n", " title=\"CZ Gate Fidelities\",\n", " xlabel=\"Qubit pairs\",\n", " ylabel=\"Fidelities\",\n", @@ -393,7 +398,7 @@ "outputs": [], "source": [ "plot_metrics(\n", - " metric=\"fidelity_2qb_cliffords_averaged\",\n", + " metric=\"clifford_rb_fidelity\",\n", " title=\"Two-qubit Gates Cliffords Averaged\",\n", " xlabel=\"Qubits\",\n", " ylabel=\"Fidelities\",\n", @@ -409,17 +414,17 @@ "## Software versions\n", "\n", "```bash\n", - "cirq-iqm==12.2\n", - "iqm-client==15.3\n", - "iqm-cortex-cli==5.8\n", - "qiskit-iqm==11.10\n", + "cirq-iqm==15.1\n", + "iqm-client==20.3\n", + "iqm-cortex-cli==5.10\n", + "qiskit-iqm==15.4\n", "```" ] } ], "metadata": { "kernelspec": { - "display_name": "helmi-cocos", + "display_name": "qc-docs", "language": "python", "name": "python3" }, @@ -433,7 +438,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.10" + "version": "3.11.10" } }, "nbformat": 4, diff --git a/docs/faq.md b/docs/faq.md index cfa3964..5ff1bd6 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -20,11 +20,11 @@ No circuit optimization is performed after the circuit has been submitted in ser **Q: Is heralding enabled on Helmi?** -[Heralding](https://iqm-finland.github.io/iqm-client/api/iqm.iqm_client.iqm_client.HeraldingMode.html#iqm.iqm_client.iqm_client.HeraldingMode) is an optional feature that allows for post-selection of shots, to filter out runs where one or more qubits were not in the ground state at the beginning of the circuit execution. The feature is currently unavailable on Helmi. +[Heralding](https://iqm-finland.github.io/iqm-client/api/iqm.iqm_client.iqm_client.HeraldingMode.html#iqm.iqm_client.iqm_client.HeraldingMode) is an optional feature that allows for post-selection of shots, to filter out runs where one or more qubits were not in the ground state at the beginning of the circuit execution. This feature is available in VTT quantum computers but it is not officially supported by IQM and your mileage may vary. **Q: What is the time-to-execution after a job has been scheduled on Helmi?** -An overhead of 10 seconds can be expected. The largest overhead is introduced by compiling the pulses to instructions for the control electronics and the upload to the instruments. +An overhead of 6 seconds can be expected. The largest overhead is introduced by compiling the pulses to instructions for the control electronics and the upload to the instruments. **Q: Does the number of shots affect the calibration of Helmi?** @@ -32,8 +32,8 @@ No, a large number of shots will not cause thermal excitations of the qubits. **Q: Can Pennylane be used on Helmi?** -Yes, Pennylane can be used on Helmi through a [fork of the Pennylane-Qiskit package](https://github.com/NordIQuEst/pennylane-qiskit/tree/support-num-qubits). This is demonstrated in the [Introduction to Helmi with Qiskit example](examples/intro-to-helmi-qiskit.ipynb#pennylane-qiskit). +No, Pennylane is not currently supported on Helmi; but pennylane-qiskit may or may not work. **Q: Is Qiskit v1.0 supported on Helmi?** -Qiskit 1.0 is not currently supported on Helmi. Please refer to the [v0.45.3 API documentation](https://docs.quantum.ibm.com/api/qiskit/0.45). +Qiskit 1.1 is now supported on Helmi. Please refer to the [v1.1.2 API documentation](https://docs.quantum.ibm.com/api/qiskit/1.1). diff --git a/docs/helmi.md b/docs/helmi.md index e715bc6..59aeb18 100644 --- a/docs/helmi.md +++ b/docs/helmi.md @@ -16,9 +16,9 @@ To run arbitrary quantum circuits, a QPU needs to implement a universal gate set - Single-qubit gates: Phased-$RX$ gate (PRX) - Two-qubit gate: Controlled-$Z$ gate (CZ) +MOVE Gates are not natively implemented on Helmi. Measurements are natively implemented as single-qubit measurements in the $Z$ basis. - ## Characteristics The values below are averaged values. Actual values might differ from day-to-day. @@ -39,7 +39,13 @@ The coupler characteristics are given below. TC refers to tunable coupler. | --------------------------------- | ------ | ------ | ------ | ------ | | Two-qubit Gate Fidelities[^3] [%] | 96.4 | 95.9 | 94.6 | 97.5 | -The PRX gate length and the CZ gate length is 120 [ns] respectively. +The CZ gate length are (note that these gate lengths may vary): + +| | QB-3-1 | QB-3-2 | QB-3-4 | QB-3-5 | +| ------------------------- | ------ | ------ | ------ | ------ | +| CZ Gate Length [ns] | 106.6 | 113.3 | 93.3 | 106.6 | + +The PRX Gate Length is 120 ns for all qubits. [^1]: [*Long-Distance Transmon Coupler with cz-Gate Fidelity above 99.8%, Marxer et al.*](https://doi.org/10.1103/PRXQuantum.4.010314) [^2]: Calculated via randomized benchmarking diff --git a/docs/limitations.md b/docs/limitations.md index cdb6b26..3f677d1 100644 --- a/docs/limitations.md +++ b/docs/limitations.md @@ -7,22 +7,13 @@ hide: There are a number of limitations on Helmi that need to be taken into account when writing quantum circuits. -**Queue length** - -To ensure manageable wait times, the job queue can accommodate up to **100 sequential jobs**. -Jobs when the queue reached its limit will be denied, triggering the following error message from the IQM client: - -```bash -ClientAuthenticationError: Authentication failed: {"detail":"Job rejected: Too many circuits in queue"} -``` - **Batch size** -On our Helmi system, quantum circuits within a batch are processed sequentially. To prevent extensive queue occupation by large batches, we have set a maximum limit of **20 circuits per batch**. -Jobs submitting batches with more than 20 circuits will be rejected and the IQM client will return the following error +On our Helmi system, quantum circuits within a batch are processed sequentially. To prevent extensive queue occupation by large batches, we have set a maximum limit of **200 circuits per batch**. +Jobs submitting batches with more than 200 circuits will be rejected and the IQM client will return the following error ```bash -ClientAuthenticationError: Authentication failed: {"detail":"Too many circuits X in batch (max: 20)"} +ClientConfigurationError: Client configuration error: {"error":"Request contains x circuits in batch which is larger than maximum number of circuits (200) allowed per batch for device Helmi."} ``` Here, 'X' denotes the actual number of circuits attempted to be included in the batch. diff --git a/docs/lumi.md b/docs/lumi.md index 5580f5b..d1d133a 100644 --- a/docs/lumi.md +++ b/docs/lumi.md @@ -45,9 +45,9 @@ Loading `helmi_qiskit` or `helmi_cirq` on LUMI comes with a preconfigured Python | Package | Version | | --------------------------------------------------- | -------------- | -| [iqm-client ](https://pypi.org/project/iqm-client/) | >=15.2 < 16.0 | -| [qiskit-iqm](https://pypi.org/project/qiskit-iqm/) | >=11.10 < 12.0 | -| [cirq-iqm](https://pypi.org/project/qiskit-iqm/) | >=12.2 < 13.0 | +| [iqm-client ](https://pypi.org/project/iqm-client/) | >=20.0 < 21.0 | +| [qiskit-iqm](https://pypi.org/project/qiskit-iqm/) | >=15.1 < 16.0 | +| [cirq-iqm](https://pypi.org/project/qiskit-iqm/) | >=15.1 < 16.0 | diff --git a/docs/running.md b/docs/running.md index 054d178..626a13e 100644 --- a/docs/running.md +++ b/docs/running.md @@ -1,9 +1,14 @@ # Running on Helmi -To run interactive jobs on LUMI the [`srun`](https://slurm.schedmd.com/srun.html) command can be used +To run interactive jobs on LUMI the [`srun`](https://slurm.schedmd.com/srun.html) command can be used. First we allocate resources for the job: ```bash -srun --account=project_ -t 0:02:00 -c 1 -n 1 --partition q_industry python qiskit_flip.py +salloc -n 1 -c 1 -t 00:15:00 --job-name= --account=project_ --partition q_industry +``` +Then we run our script + +```bash +srun python qiskit_flip.py ``` The command takes a number of arguments @@ -13,8 +18,6 @@ The command takes a number of arguments - `-c`: Requests that $n$ CPUs be allocated per process. - `-n`: Number of tasks to run in parallel. If greater than 1, a job may be assigned to multiple nodes. - `--partition`: The partition to run on. Should be `q_industry`. -- `cmd`: The command to run. In this case `python qiskit_flip.py` - Note, that the `srun` command is blocking, which means that you'll have to wait until your program terminates before `srun` returns and you can enter your next command. Alternatively you can also load a shell on the compute node to provide more flexibility. This can be done with the following command: