Unpack the Stack - Intro to Quantinuum’s Next-Generation Stack

Date: 2025/09/18

Presenter: Seyon Sivarajah

YouTube Link: https://www.youtube.com/watch?v=TkFGY5tHaQI

Quantinuum launched a new software stack for the next-generation Helios and future generation systems, including Guppy, a new, open-source programming language, and Selene, which can emulate a subset of Helios. During this technical webinar from September 18, 2025, Seyon Sivarajah, Principal Manager of Software Engineering, provides a deep dive into the features and benefits of the new stack, and how it enables a lower barrier to entry, faster time-to-solution, industry-standard access, and the best possible user experience.

Installation

%pip install qnexus guppylang

Notebook

from datetime import datetime


from guppylang.decorator import guppy
from guppylang.std.quantum import h, cx, measure, discard_array, qubit
from guppylang.std.builtins import array, result, py
from guppylang.emulator.result import EmulatorResult

QEC: flagged Steane state preparation

We will implement the following circuit in Guppy:

"""Steane code implementation in Guppy.
Based on https://arxiv.org/abs/2107.07505.
"""


SEED = 42
N_SHOTS = 1000
N_QUBITS = 8


@guppy.struct
class SteaneQ:
    data_qs: array[qubit, 7] # type: ignore


@guppy
def non_ft_zero() -> SteaneQ:
    """Non-fault-tolerant preparation of |0>_L in the Steane code."""
    data_qubits = array(qubit() for _ in range(7)) # type: ignore
    plus_ids = array(0, 4, 6)
    for i in plus_ids:
        h(data_qubits[i])

    cx_pairs = array((0, 1), (4, 5), (6, 3), (6, 5), (4, 2), (0, 3), (4, 1), (3, 2))
    for c, t in cx_pairs:
        cx(data_qubits[c], data_qubits[t])
    return SteaneQ(data_qubits)


@guppy
def flagged_ft_zero() -> tuple[SteaneQ, bool]:
    """Fault-tolerant preparation of |0>_L in the Steane code,
    with flag qubits to detect errors.
    Returns the prepared logical qubit and a flag indicating if an error was detected.
    """
    q = non_ft_zero()
    ancilla = qubit() # type: ignore
    flags = array(1, 3, 5)
    for f in flags:
        cx(q.data_qs[f], ancilla)
    return q, measure(ancilla)

 
MAX_ATTEMPTS = 1000

@guppy
def count_attempts() -> None:
    """Attempt fault-tolerant zero preparation multiple times,
    until success or the maximum number of attempts is reached.
    """
    
    for attempt in range(py(MAX_ATTEMPTS)):
        q, failed = flagged_ft_zero()
        discard_array(q.data_qs)
        if not failed:
            result("attempt", attempt)
            break


count_attempts.check()
def mean_attempts(res: EmulatorResult) -> None:
    """Utility function to compute and print the mean number of attempts"""
    mean = sum(shot.as_dict()["attempt"] + 1 for shot in res)/len(res) # type: ignore
    print(f"Mean attempts: {mean}")

Create a new Nexus project

import qnexus as qnx
from quantinuum_schemas.models.emulator_config import QSystemErrorModel

my_project_ref = qnx.projects.get_or_create(name="Selene-Nexus")
qnx.context.set_active_project(my_project_ref)

Configure the Nexus emulator and submit job

Run our experiment remotely on Nexus, emulating the real quantum hardware.

# Upload our program to Nexus
program_ref = qnx.hugr.upload(
    hugr_package=count_attempts.compile(),
    name="steane_code_attempts",
)

# Define our Selene configuration
config = qnx.models.StandardEmulatorConfig(
    n_qubits=N_QUBITS,
    runtime=qnx.models.HeliosRuntime(seed=SEED),
    # DEMO QSystemErrorModel - not representative of actual hardware at launch
    error_model=QSystemErrorModel(seed=SEED),
    simulator=qnx.models.StabilizerSimulator(seed=SEED)
 )

# Start the job on Nexus
selene_quest_job_ref = qnx.start_execute_job(
    programs=[program_ref],
    n_shots=[N_SHOTS],
    backend_config=config,
    name=f"steane_code_attempts {datetime.now()}",
)

Run emulation locally

First run with no errors, state preparation should succeed in 1 attempt on average.

emulator = (
    count_attempts
    .emulator(n_qubits=N_QUBITS)
    .stabilizer_sim()
    .with_seed(SEED)
    .with_shots(N_SHOTS)
    .with_progress_bar()
)

mean_attempts(emulator.run())

Let’s emulate with a simple depolarizing noise model, now we should detect some failures and the mean attempts should be higher.

from selene_sim.backends.bundled_error_models import DepolarizingErrorModel
error_model = DepolarizingErrorModel(
    # single qubit gate error rate
    p_1q=1e-3,
    # two qubit gate error rate
    p_2q=2e-3,
)

mean_attempts(emulator.with_error_model(error_model).run())

Retrieve results from Nexus

Since we are emulating the device we can expect some retries.

qnx.jobs.wait_for(selene_quest_job_ref)

nexus_result = qnx.jobs.results(selene_quest_job_ref)[0].download_result()
mean_attempts(nexus_result) # type: ignore