Skip to content

Negative indices and negative ranges are rejected on arrays, registers and aliases #391

Description

@TheGupta2012

Limitation

OpenQASM 3 indexes from the end with negative integers, where -1 is the last element. The
spec uses this in Arrays,
Classical value bit slicing and
Register concatenation and slicing.

pyqasm treats every index as non-negative. Negative indices either produce an
out-of-range error or a generic initialisation error.

Example QASM failure

Arrays — straight from the spec's Arrays section:

OPENQASM 3.0;
array[int[32], 5] myArray = {0, 1, 2, 3, 4};
int[32] alsoLastElem = myArray[-1];        // 4
// ValidationError: Invalid initialization value for variable 'alsoLastElem'
OPENQASM 3.0;
array[float[32], 3, 2] multiDim = {{1.1, 1.2}, {2.1, 2.2}, {3.1, 3.2}};
float[32] alsoLastLastElem = multiDim[-1, -1];   // 3.2
// ValidationError: Invalid initialization value for variable 'x'

Negative index as an assignment target:

OPENQASM 3.0;
array[int[32], 5] a = {0, 1, 2, 3, 4};
a[-1] = 10;
// ValidationError: Invalid index for variable 'a'

Qubit registers:

OPENQASM 3.0;
include "stdgates.inc";
qubit[4] q;
h q[-1];
// ValidationError: Index -1 out of range for register of size 4 in qubit

Negative ranges, from the spec's Register concatenation and slicing section:

OPENQASM 3.0;
qubit[6] two;
let last_three = two[-4:-1];
// ValidationError: Index -4 out of range for register of size 6 in qubit

Bit registers:

OPENQASM 3.0;
bit[4] b = "1010";
bit c = b[-1];
// ValidationError: Invalid initialization value for variable 'c'

Change Requested

  1. Normalise a negative index i on a dimension of size n to i + n before the bounds
    check, everywhere an index is resolved.
  2. Apply the same normalisation to both endpoints of a range expression, including the
    stepped form [-4:2:-1].
  3. Support this uniformly across arrays (including multi-dimensional and assignment targets),
    bit[n], qubit[n], and let aliases.
  4. After normalisation, an index still outside [0, n) must raise the existing out-of-range
    ValidationError — reporting the index as written in the source, not the normalised value.

Implementation Details

  • The single most valuable change is a shared helper, e.g.
    Qasm3Analyzer.normalize_index(index: int, size: int, span) -> int, applied at every index
    resolution site so the behaviour cannot drift between paths.
  • Call sites to update in src/pyqasm/analyzer.py: analyze_classical_indices and the qubit
    index validation that produces "Index -1 out of range for register of size 4".
  • Range handling lives in Qasm3Transformer.get_qubits_from_range_definition
    (src/pyqasm/transformer.py:129) and get_target_qubits
    (src/pyqasm/transformer.py:383). Both endpoints need normalising before the range is
    expanded, and the step sign must still be honoured afterwards.
  • Watch the interaction with remove_idle_qubits / reverse_qubit_order, which rewrite
    indices post-unroll. Since normalisation happens during resolution, they should see only
    concrete non-negative indices — worth an explicit test to confirm.
  • Note the spec's reversed form myInt[-1:-16], which is a descending range. Confirm the
    intended iteration order and cover it.
  • Tests: extend tests/qasm3/ array, alias and measurement tests with negative reads, negative
    writes, negative ranges, stepped negative ranges, and an out-of-range negative index that
    must still error.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or requestllm-assistedUsed LLMs to fine tune issue description.qasm3Related to openqasm3qasm3-coverageAdding support for qasm3 constructs

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions