Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Qamomile v0.15.1

Breaking Changes

Return an executable from HugrTranspiler.transpile()

HugrTranspiler.transpile() now returns a HugrExecutable with run() and sample() methods, following the execution pattern used by other engines. Code that needs the CompiledProgram returned in v0.15.0 should call HugrTranspiler.compile() instead.

Feature Enhancements

GASConverter adds circuit generation for Grover Adaptive Search (GAS), which repeatedly uses quantum search to find better solutions. It accepts a BinaryModel or an OMMX optimization problem and supports quadratic and higher-order binary objectives (QUBO/HUBO). For a specified threshold and number of Grover iterations, it builds a circuit to search for candidates below that threshold and converts measurement results back into candidate variable assignments.

To implement the full search, write the Python loop that evaluates candidates, updates the threshold and iteration count, and decides when to stop. Non-integer coefficients are approximated by scaled integers by default, so the results may include approximation error.

See the Grover Adaptive Search documentation.

Execute programs on IBM Quantum hardware

Qamomile quantum programs can now run on IBM Quantum hardware through QiskitExecutor. This requires installing qamomile[qiskit] and configuring an IBM Quantum account and instance.

See Qiskit Support.

Execute HUGR programs with Selene or Helios

Programs converted to the HUGR intermediate representation can now be executed with the local Selene simulator or on Quantinuum Helios through Nexus. Install qamomile[hugr] to use this integration; Helios also requires a configured Nexus account and project.

Measure a qubit register as an unsigned integer with QInt

qmc.cast(register, qmc.QInt) interprets a Vector[Qubit] as an unsigned quantum integer, and qmc.measure() returns a qmc.UInt. The register’s first qubit is the least-significant bit. Casting reuses the same qubits and consumes the source handle, so subsequent operations must use the returned handle.

QInt values can also be passed as arguments and returned from direct quantum-kernel calls.

import qamomile.circuit as qmc
from qamomile.qiskit import QiskitTranspiler


@qmc.qkernel
def measure_integer() -> qmc.UInt:
    register = qmc.qubit_array(3, "register")
    register[0] = qmc.x(register[0])
    register[1] = qmc.x(register[1])
    integer = qmc.cast(register, qmc.QInt)
    return qmc.measure(integer)


transpiler = QiskitTranspiler()
executable = transpiler.transpile(measure_integer)

This example measures the integer 3. QInt uses the whole register width; omit int_bits, which is only accepted for QFixed. Slice bounds must be constant for a cast.

HUGR supports QInt measurement for registers whose width is known at transpilation, from 0 through 64 bits. This width limit applies only to HUGR. See HUGR: measuring quantum integers for usage and limitations.

Save and restore jobs containing local results

job.snapshot() can now save retrieved local results, including constant expectation values, alongside remote jobs. Restoring a group preserves every result’s type and position, including groups containing both local results and remote jobs. Restoration reuses the saved results and submitted jobs without resubmitting quantum jobs. For local Braket execution, retrieve the result with result() before saving a snapshot.

Use the same executable and original runtime arguments when restoring; credentials and runtime arguments are not stored in snapshots. Previously saved remote-job snapshots remain supported.

Bugfixes

Preserve QFixed widths and values through compilation and serialization

QFixed casts now support a symbolic register width with a nonzero, constant int_bits. Compile-time branches selecting registers of different widths rebuild the selected fixed-point layout correctly. Measurement decoding, resource estimation, and serialization preserve the selected qubits and their order, including constant-bound slices and values passed through quantum-kernel calls. Unresolvable measurement widths are reported as SeparationError instead of being treated as empty registers.

Returning a QFixed measurement together with measurements of other registers from the same quantum kernel could cause transpilation to fail. These results can now be returned together, including combinations with QInt measurements, while preserving each result’s type and return order.

Draw packed registers correctly after restoring a quantum kernel

Circuit diagrams retain the actual qubit wires and measurement destinations of QFixed and QInt registers after serialization and deserialization. This also corrects register placement for sliced registers and packed values returned from other quantum kernels.

Reject invalid measurement counts from QURI Parts samplers

QuriPartsExecutor passed sampler counts through without validating them, allowing fractional or negative values to appear as measurement counts. Invalid counts now raise ValueError. Whole-valued scalars such as 3.0 are converted to Python int values.

Attempt cancellation of every unfinished job in a group

Cancellation now attempts every unfinished child even when another child’s status check or cancellation fails. Any failures are reported together as an ExceptionGroup after all children have been visited; callers handling provider errors from grouped cancellation should handle this aggregate exception.

Other Changes