RNG Capability

Note

Pytket only supports random 32-bit integer generation and this is only executable on select Quantinuum targets.

  • Floating-point numbers cannot be randomly generated with pytket.

  • Emulator targets suffixed with E are supported. Nexus-hosted emulators and local emulators are not supported.

  • Execution is only possible if OpenQASM is selected as the language option upon execute job submission.

System Model H2 provides an integrated pseudo Random Number Generator (RNG) capability with the pytket circuit builder API (pytket.circuit). This enables generation and consumption of random integers during real-time program execution. The RNG capability is also available on Quantinuum Helios via Guppy. The RNG capability is executed on the control system (ARM Cortex processor).

Usage

Pytket’s circuit builder API provides instance methods to perform RNG operations on classical bit registers. The exact register size required to use the available RNG functions is specified the table below.

Function

Classical Register Width

tket:pytket.circuit.set_rng_seed()

64

tket:pytket.circuit.set_rng_bound()

32

tket:pytket.circuit.set_rng_index()

32

tket:pytket.circuit.get_rng_num()

32

Set RNG Seed

tket:pytket.circuit.set_rng_seed()

Seed an RNG from the contents of a classical register.

The classical register must be exactly 64 bits.

circ = Circuit()

creg = circ.add_c_register("c", 64)
circ.add_c_setbits([True, True], [creg[3], creg[11]])
circ.set_rng_seed(creg)

Set RNG Bound

tket:pytket.circuit.set_rng_bound()

Set an RNG upper bound from the contents of a classical register. The exact sequence of random numbers can be reproduced by setting the same master seed and stream index.

The classical register must be exactly 32 bits. It encodes the upper bound in little-endian binary (least significant bit first). The bound is inclusive.

circ = Circuit()
creg = circ.add_c_register("c", 32)
circ.add_c_setbits([True, True], [creg[3], creg[11]])
circ.set_rng_bound(creg)

Set RNG Index

tket:pytket.circuit.set_rng_index()

Set an RNG stream index from the contents of a classical register.

The classical register must be exactly 32 bits. It encodes the index in little- endian binary (least significant bit first).

circ = Circuit()
creg = circ.add_c_register("c", 32)
circ.add_c_setbits([True, True], [creg[3], creg[11]])
circ.set_rng_index(creg)

Set RNG Numbers

tket:pytket.circuit.get_rng_num()

Get RNG output into a classical register.

The classical register must be exactly 32 bits. After the operation it encodes the output number in little-endian binary (least significant bit first).

circ = Circuit()
creg = circ.add_c_register("c", 32)
circ.get_rng_num(creg)

Use Case: Adaptive Circuit Synthesis

The code sample generates random bounded 32-bit integers between ([0, 3)). The random integers correspond to the following physical operations with a native tket:pytket.circuit.Circuit.PhasedX(). The function, tket:pytket.circuit.Circuit.add_c_setreg(), is used to set a specified classical register to an integer value.

The PhasedX operation is used to perform the following Pauli operations:

  1. Pauli-X,

  2. Pauli-Y,

  3. Pauli-Z,

from pytket.circuit import Circuit
from pytket.circuit.logic_exp import reg_eq

circuit = Circuit(1)
seed = circuit.add_c_register("seed", 64)

bound = circuit.add_c_register("bound", 32)
circuit.add_c_setreg(1, bound)
circuit.add_c_setreg(3, bound)

index = circuit.add_c_register("index", 32)
op = circuit.add_c_register("op", 32)

# for _ in range(5):
circuit.get_rng_num(op)
circuit.PhasedX(1, 0, 0, condition=reg_eq(op, 0))
circuit.PhasedX(0, 1, 0, condition=reg_eq(op, 1))
circuit.PhasedX(1, 1, 0, condition=reg_eq(op, 2))

circuit.measure_all()
circuit.n_bits

The circuit can be submitted to Quantinuum emulators or hardware via the usual Nexus workflow.

import qnexus as qnx
import uuid

project = qnx.projects.get_or_create("RNG")
qnx.context.set_active_project(project)
resource_suffix = uuid.uuid1()

Quantinuum Backend configuration

config = qnx.QuantinuumConfig(
    device_name="H2-2E",
)

Circuit upload to Nexus database.

circ_ref = qnx.circuits.upload(circuit=circuit, name=f"rng-circuit-{resource_suffix}")

Server-side Circuit Compilation

compile_ref = qnx.start_compile_job(
    programs=[circ_ref],
    name=f"compile-job-{resource_suffix}",
    optimisation_level=0,
    backend_config=config
)
qnx.jobs.wait_for(compile_ref)
ref_compile_circuit = qnx.jobs.results(compile_ref)[0].get_output()

Execute job submission

execute_ref = qnx.start_execute_job(
    programs=[ref_compile_circuit],
    name=f"execute-job-{resource_suffix}",
    n_shots=[100],
    backend_config=config,
    language=qnx.models.language.Language.QASM
)
qnx.jobs.wait_for(execute_ref)
result_ref = qnx.jobs.results(execute_ref)[0]
execute_ref
backend_result = result_ref.download_result()
print(backend_result.get_distribution())

Conversions

OpenQASM

from pytket.qasm import circuit_to_qasm_str

qasm_str = circuit_to_qasm_str(circuit, header="hqslib1", maxwidth=64)
with open("rng.qasm", "w") as file_io:
    file_io.write(qasm_str)

QIR

from pytket.qir import pytket_to_qir, QIRFormat

qir_str = pytket_to_qir(circuit, qir_format=QIRFormat.STRING)
with open("rng.ll", "w") as file_io:
    file_io.write(qir_str)