{ "cells": [ { "cell_type": "markdown", "id": "b8977f79", "metadata": {}, "source": [ "# Helios and Selene" ] }, { "cell_type": "markdown", "id": "c666713b", "metadata": {}, "source": [ "Helios is Quantinuum's third generation quantum processessing unit, [announced](https://www.quantinuum.com/press-releases/quantinuum-announces-commercial-launch-of-new-helios-quantum-computer-that-offers-unprecedented-accuracy-to-enable-generative-quantum-ai-genqai) in November of 2025. Up-to-date technical specifications can be found in the [Helios product data sheet](https://docs.quantinuum.com/systems/data_sheets/Quantinuum%20Helios%20Product%20Data%20Sheet.pdf). You can read more about Helios in the [introductory blog](https://www.quantinuum.com/blog/introducing-helios-the-most-accurate-quantum-computer-in-the-world), [benchmark paper](https://arxiv.org/pdf/2511.05465), or [documentation](https://docs.quantinuum.com/systems/trainings/helios/getting_started/index.html).\n", "\n", "With Helios comes a new software stack, including [Selene](https://docs.quantinuum.com/selene/index.html), Quantinuum's emulation framework for hybrid (quantum/classical) programs. Selene is a very useful simulation tool that can be used both locally or remotely via Nexus.\n", "\n", "This tutorial shows the user how to instantiate and submit jobs to Helios and Selene. As submission to these new backends is the focus, we extract a Hamiltonian for H2 in the STO-3G basis from the `express` module. Then, we build a trial state with a Trotter ansatz. The ground state energy of this system is then estimated with the Pauli averaging protocol." ] }, { "cell_type": "code", "execution_count": null, "id": "e8e1da4e", "metadata": {}, "outputs": [], "source": [ "from inquanto.express import load_h5\n", "from inquanto.operators import QubitOperator,QubitOperatorList\n", "from inquanto.states import QubitState\n", "from inquanto.ansatzes import TrotterAnsatz\n", "from inquanto.computables import ExpectationValue\n", "from inquanto.protocols import PauliAveraging\n", "from pytket.partition import PauliPartitionStrat\n", "\n", "\n", "h2 = load_h5(\"h2_sto3g.h5\", as_tuple=True)\n", "hamiltonian = h2.hamiltonian_operator.qubit_encode()\n", "\n", "exponents = QubitOperatorList(QubitOperator(\"Y0 X1 X2 X3\", 1j), -0.111)\n", "reference = QubitState([1, 1, 0, 0])\n", "ansatz = TrotterAnsatz(exponents, reference)\n", "\n", "energy = ExpectationValue(ansatz, hamiltonian)" ] }, { "cell_type": "markdown", "id": "00c7257a", "metadata": {}, "source": [ "## Submitting to Helios\n", "\n", "With the system defined, we need to choose a backend. First we demonstrate how to access and use a Helios backend with `qnexus`.\n", "\n", "Once the user has logged in with their Quantinuum Nexus credentials, we create a reference to a Nexus project. Then we define a backend configuration, specifying a number of backend parameters. In this case, we use a `HeliosConfig`.\n", "\n", "The `HeliosConfig` must be instantiated with a `system_name` and `max_cost`. Here we specify Helios-1E, the Helios emulator, and a `max_cost` of 500. The `max_cost` argument sets a maximum threshold for the number of HQCs that a job can consume. This is required as Helios - and all related backends - can execute dynamic, hybrid programs with classical control flow. A consequence of this is that the cost of running a particular program is not statically known at runtime. If a job exceeds this threshold, it is terminated and any results of completed measurements are returned to the user.\n", "\n", "Finally, the number of qubits, `n_qubits` must be defined in a `HeliosEmulatorConfig` as an upper bound that ensures the emulator runs efficiently." ] }, { "cell_type": "code", "execution_count": null, "id": "4de4491c", "metadata": {}, "outputs": [], "source": [ "from qnexus.client import auth, projects\n", "from qnexus.models import HeliosConfig, HeliosEmulatorConfig, StatevectorSimulator\n", "\n", "# Login with Quantinuum Nexus credentials.\n", "# auth.login()\n", "\n", "project_ref = projects.get_or_create(name=\"InQuanto Documentation\")\n", "\n", "helios_config = HeliosConfig(\n", " system_name=\"Helios-1E\",\n", " max_cost = 500,\n", " emulator_config=HeliosEmulatorConfig(\n", " n_qubits=10, \n", " )\n", ")" ] }, { "cell_type": "markdown", "id": "912554f7", "metadata": {}, "source": [ "With the backend defined, we can then instantiate, build, and compile a `PauliAveraging` protocol, remembering to include the reference to a Nexus project through the `project_ref`. \n", "\n", "It should be noted that the compilation step for these backends (Helios hardware and emulators, including Selene) is not quite the same as for other backends. There are no pre-defined compilation passes that can be applied by invoking the `optimization_level` argument when calling `compile_circuits()`. However, users can still define and apply their own sets of passes with the `preoptimize_passes` and `compiler_passes` arguments as outlined in the [circuit compilation tutorial](https://docs.quantinuum.com/inquanto/tutorials/InQ_tut_circ_comp.html). " ] }, { "cell_type": "code", "execution_count": null, "id": "c24f20c8", "metadata": {}, "outputs": [], "source": [ "\n", "helios_protocol = PauliAveraging(\n", " backend=helios_config,\n", " shots_per_circuit=1000,\n", " pauli_partition_strategy=PauliPartitionStrat.CommutingSets,\n", " project_ref=project_ref\n", ")\n", "helios_protocol.build_from({}, energy)\n", "helios_protocol.compile_circuits()\n" ] }, { "cell_type": "markdown", "id": "9fae4064", "metadata": {}, "source": [ "Here, we use an asynchronous workflow to first launch and then retrieve the job from the remote emulator once it has completed." ] }, { "cell_type": "code", "execution_count": null, "id": "01851116", "metadata": {}, "outputs": [], "source": [ "handles = helios_protocol.launch()\n", "helios_protocol.retrieve(handles)" ] }, { "cell_type": "code", "execution_count": null, "id": "574e0946", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Number of circuits: 2\n" ] }, { "data": { "text/plain": [ "-1.1284691520823564" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "print(\"Number of circuits: \", helios_protocol.n_circuit)\n", "\n", "energy.evaluate(helios_protocol.get_evaluator())" ] }, { "cell_type": "markdown", "id": "ee72a053", "metadata": {}, "source": [ "## Selene\n", "\n", "Now, we turn to Selene. More specifically, we take advantage of the QuEST state vector simulator. In this case, we are using a local backend and as such the definition of a Nexus project reference or `qnexus` config are not needed and we can simply instantiate Selene via InQuanto's `hugr` module. This module is named after the hierarchical unified graph representation (HUGR), an intermediate representation of quantum circuits developed for the Quantinuum ecosystem. However, users do not need to interact with or manipulate so called \"HUGRs\" to use Selene or Helios with InQuanto. \n", "\n", "Whilst here we demonstrate running Selene locally here, you can also submit Selene jobs to Nexus using with a `qnexus.SeleneConfig`. " ] }, { "cell_type": "code", "execution_count": null, "id": "07fe356d", "metadata": {}, "outputs": [], "source": [ "from inquanto.hugr.hugr_utils import SELENE\n", "\n", "backend = SELENE.QUEST" ] }, { "cell_type": "code", "execution_count": null, "id": "49464bbf", "metadata": {}, "outputs": [], "source": [ "selene_protocol = PauliAveraging(\n", " backend=backend,\n", " shots_per_circuit=1000,\n", " pauli_partition_strategy=PauliPartitionStrat.CommutingSets,\n", ")\n", "selene_protocol.build_from({}, energy)\n", "selene_protocol.compile_circuits()" ] }, { "cell_type": "markdown", "id": "16170c7b", "metadata": {}, "source": [ "Instead of launching and retrieving this job asynchronously, we use `run()`." ] }, { "cell_type": "code", "execution_count": null, "id": "4aab555e", "metadata": {}, "outputs": [], "source": [ "selene_protocol.run()" ] }, { "cell_type": "code", "execution_count": null, "id": "16bec538", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Number of circuits: 2\n" ] }, { "data": { "text/plain": [ "-1.1357335665698658" ] }, "execution_count": null, "metadata": {}, "output_type": "execute_result" } ], "source": [ "print(\"Number of circuits: \", selene_protocol.n_circuit)\n", "\n", "energy.evaluate(selene_protocol.get_evaluator())" ] } ], "metadata": {}, "nbformat": 4, "nbformat_minor": 5 }