Parameterized Shots

The Helios platform provides a function call to get the shot index. The user program can be parameterized by the shot index. The shot index can be returned in Guppy using guppylang.std.qsystem.utils.get_current_shot().

Use Case 1: RNG Seed

The seed value can be unique per shot using guppylang.std.qsystem.utils.get_current_shot(). In the code sample provided, the seed is incremented every shot. The RNG object is instantiated every shot and used to generate 32-bit random floats.

from guppylang import guppy
from guppylang.std.angles import angle
from guppylang.std.builtins import result, comptime, array
from guppylang.std.quantum import qubit, measure_array
from guppylang.std.qsystem import zz_phase
from guppylang.std.qsystem.utils import get_current_shot
from guppylang.std.qsystem.random import RNG

INIT_SEED = 0

N = 18
nlayer = 3

@guppy
def layer(
    q: array[qubit, comptime(N)],
    rng: RNG,
    index_shift: bool
) -> None:
    a = array(rng.random_float() for _ in range(comptime(N//2)))
    result("angle", a)
    for k in range(comptime(N//2)):
        i = 2 * k + int(index_shift)
        j = 2 * k + 1 + int(index_shift)
        if i >= comptime(N):
            i = i - comptime(N)
        if j >= comptime(N):
            j = j - comptime(N)
        zz_phase(q[i], q[j], angle(a[k]))

@guppy
def main() -> None:
    q_array = array(qubit() for _ in range(comptime(18)))
    rng = RNG(comptime(INIT_SEED) + get_current_shot())
    for _ in range(comptime(nlayer)):
        layer(q_array, rng, False)
        layer(q_array, rng, True)
    r_array = measure_array(q_array)
    result("mresult", r_array)
    rng.discard()

hugr_binary = main.compile()
import qnexus as qnx
import uuid

unique_suffix = uuid.uuid1()

project = qnx.projects.get_or_create("Helios-Samples")
qnx.context.set_active_project(project)

ref_hugr = qnx.hugr.upload(
    hugr_binary, 
    name=f"rng-usecase0-{unique_suffix}"
)
from quantinuum_schemas import HeliosConfig, HeliosEmulatorConfig, CoinflipSimulator

helios_config = HeliosConfig(
    system_name="Helios-1E-lite",
    emulator_config=HeliosEmulatorConfig(
        simulator=CoinflipSimulator(),
        n_qubits=18
    ),
    max_cost=100
)
result_ref = qnx.start_execute_job(
    programs=[ref_hugr],
    n_shots=[1],
    backend_config=helios_config,
    name=f"job-rng-usecase0-{unique_suffix}"
)
qnx.jobs.wait_for(result_ref)
job_result = qnx.jobs.results(result_ref)[0].download_result()
print(job_result)
QsysResult(results=[QsysShot(entries=[['angle', [0.13170378981158137, 0.755355317145586, 0.5831400000024587, 0.21037689154036343, 0.9376081398222595, 0.6338424978312105, 0.7061422956176102, 0.06342564942315221, 0.2751847072504461]], ['angle', [0.004724327474832535, 0.18847966892644763, 0.5039901344571263, 0.3183173837605864, 0.14421830116771162, 0.08386536641046405, 0.2119857717771083, 0.6731340079568326, 0.6624895462300628]], ['angle', [0.6486093683633953, 0.6693849647417665, 0.632575634168461, 0.2803243848029524, 0.8352232179604471, 0.03838327317498624, 0.12490360159426928, 0.7011869826819748, 0.9515982016455382]], ['angle', [0.5227349053602666, 0.2847847656812519, 0.27109970338642597, 0.2859301823191345, 0.07285637431778014, 0.8271915337536484, 0.22953439853154123, 0.8056983519345522, 0.12264243187382816]], ['angle', [0.7009257823228836, 0.4759937422350049, 0.027518346207216385, 0.925707106012851, 0.2213007945101708, 0.3689842042513192, 0.6145194519776851, 0.9821490130852908, 0.18022531014867127]], ['angle', [0.4735962741542607, 0.9543152288533748, 0.8398035247810185, 0.4232349132653326, 0.3869804949499666, 0.9539077635854484, 0.251403326401487, 0.9643704514019192, 0.7240403406322002]], ['mresult', [0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1]]])])

Use Case 2: Parameterized Angles

Pre-generated angles can be parameterized using the current shot index. The code sample generates a 4 Pauli Exponential primitives across 4-qubits and then measures the qubits. This process is repeated 4 times. The qubits are implictly reused via dynamic qubit allocation.

import numpy as np

from guppylang import guppy
from guppylang.std.angles import angle
from guppylang.std.quantum import cx, rz, measure_array, qubit
from guppylang.std.builtins import comptime, array
from guppylang.std.qsystem.utils import get_current_shot

P = np.random.random_sample((4, 4)) / np.pi

@guppy
def gadget(
    gate_angle: angle,
    q_array: array[qubit, 4]
) -> None:
    for i in range(3):
        cx(q_array[i], q_array[i+1])
    rz(q_array[3], gate_angle)
    for i in range(1, 3):
        cx(q_array[4-i-1], q_array[4-i])


@guppy
def main() -> None:
    params_set = comptime(P.tolist())
    shot_index = get_current_shot()
    param = array(p for p in params_set[shot_index])
    result("parameters", param)
    for _ in range(4):
        q_array = array(qubit() for _ in range(4))
        for i in range(4):
            gadget(angle(param[i]), q_array)
        outcome = measure_array(q_array)
        result("measurements", outcome)
hugr_binary = main.compile()

ref_hugr = qnx.hugr.upload(
    hugr_binary, 
    name=f"rng-usecase1-{unique_suffix}"
)
from quantinuum_schemas import HeliosConfig, HeliosEmulatorConfig, CoinflipSimulator

helios_config = HeliosConfig(
    system_name="Helios-1E-lite",
    emulator_config=HeliosEmulatorConfig(
        simulator=CoinflipSimulator(),
        n_qubits=4
    ),
    max_cost=100
)
result_ref = qnx.start_execute_job(
    programs=[ref_hugr],
    n_shots=[1],
    backend_config=helios_config,
    name=f"job-rng-usecase1-{unique_suffix}"
)
qnx.jobs.wait_for(result_ref)
job_result = qnx.jobs.results(result_ref)[0].download_result()
print(job_result)
QsysResult(results=[QsysShot(entries=[['parameters', [0.17475093599078026, 0.07096292756164177, 0.16380001625697804, 0.22018444811175183]], ['measurements', [0, 1, 1, 0]], ['measurements', [0, 1, 0, 0]], ['measurements', [1, 1, 1, 0]], ['measurements', [1, 0, 1, 1]]])])
qnx.jobs.status(result_ref).status
<JobStatusEnum.ERROR: 'ERROR'>