open-standards/wai/quantum-conformance/qasm3/spec/arrays.qasm
Transaction Science 37dfe98d2d wai quantum-conformance/qasm3: the OpenQASM 3 corpus, run natively, under wasm32-wasip2 and in the browser
59 programs, each with what the reader must do with it: the language
specification's 21 example programs, unchanged (those that run held to
their results, the rest to the code that names the first construct the
reader cannot hold exactly, or the example's own error), and a program for
each construct with a reference written without it. stdgates.qasm applies
every standard gate once, and its reference writes each in U and CX alone.

Expectations: refused (a code), warns (every warning's code), deterministic
(every shot's outcome), distribution (exact outcome probabilities),
expectations (exact Pauli values), equivalent (a reference's unitary up to a
global phase), exact (the bit-exact circuit takes it or refuses it with a
code), outputs, timing and calibrations. bundle.json holds the cases with
their text inline for builds that read no files; a test holds it equal to
the files.

CI: wai-quantum-lang.yml runs the reader's tests, the corpus natively, the
reader built without the lowerings, and the corpus under wasm32-wasip2 by
wasmtime; wai-web's wasm32 tests read every case through the page's engine
(the wasm32 count goes from 8 to 9).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-27 19:51:34 -04:00

101 lines
4.1 KiB
Text

OPENQASM 3.0; // Version statement is optional
// ==================
// Array declarations
// ==================
// Declare 'my_ints' to be a 1D array of 8-bit signed integers, where the index
// runs from 0 to 15.
array[int[8], 16] my_ints;
// Declare 'my_doubles' to be a 2D array of double-precision floating-point
// values, where the first index runs from 0 to 7 and the second from 0 to 3.
array[float[64], 8, 4] my_doubles;
// Initialise a 1D array with fixed values.
array[uint[32], 4] my_defined_uints = {5, 6, 7, 8};
// Initialise a 2D array with fixed values.
array[float[32], 4, 2] my_defined_floats = {
{0.5, 0.5},
{1.0, 2.0},
{-0.4, 0.7},
{1.3, -2.1e-2}
};
// Initialise an array using a row of another array. Note that this copies the
// data; changes to the values in `my_defined_float_row` will not affect
// `my_defined_floats`.
array[float[32], 2] my_defined_float_row = my_defined_floats[0];
// Arrays can be defined in terms of compile-time constant dimension sizes, and
// can use expressions in the slots of their initialisers.
const uint[8] DIM_SIZE = 2;
array[int[8], DIM_SIZE, DIM_SIZE] all_ones = {{2+3, 4-1}, {3+8, 12-4}};
// =============================
// Array indexing and operations
// =============================
// Use `[]` notation to access array elements. The dimensions are
// comma-separated.
uint[8] a = my_defined_uints[0];
float[32] b = my_defined_floats[2, 1];
// The same notation is used in simple assignments.
my_defined_uints[1] = 5;
my_defined_floats[3, 0] = -0.45;
// In both, the indices can be (non-constant) expressions.
my_defined_uints[a - 1] = a + 1;
// Assignments can also be done using an array, or array slice, on the left-hand
// side, provided the right-hand side evaluates to an array of exactly the same
// shape. The assignment is done by copy, so subsequent changes to either of
// the two parts will not affect the other.
my_defined_floats[2] = my_defined_float_row;
// You can also use the slice notation to set elements. Beware that it is
// generally a logical error to read and write from overlapping slices at the
// same time, and that OpenQASM 3 makes no guarantees about which order the data
// will be read from and written to. You might clobber data if you overlap.
my_defined_floats[0:1] = my_defined_floats[2:3];
// The ``sizeof`` operator returns the size of an array's dimension.
const uint[32] dimension = sizeof(my_defined_uints); // assigns 4.
// The ``sizeof`` operator can also be used in two-argument form, where the
// second argument is the index of the dimension, counting from 0.
const uint[32] first_dimension = sizeof(my_doubles, 0); // returns 8
const uint[32] second_dimension = sizeof(my_doubles, 1); // returns 4
// If the second argument is omitted from ``sizeof`` and the given array is
// multi-dimensional, it defaults to returning the first dimension, so
// ``sizeof(my_array) == sizeof(my_array, 0)`` in all circumstances.
const uint[32] first_dimension = sizeof(my_doubles); // still 8.
// =====================
// Arrays in subroutines
// =====================
// Array arguments have a mandatory ``readonly`` or ``mutable`` specifier when
// defined in a subroutine argument list. This is because arrays are passed to
// subroutines by reference, not by value, so modifications will propagate back
// to the original data. Such modifications are only allowed for ``mutable``
// references, not ``readonly``.
def copy_3_bytes(readonly array[uint[8], 3] in_array, mutable array[uint[8], 3] out_array) {
// Within this block, ``in_array`` can be read from, but not written to,
// whereas ``out_array`` can be both read from and written to.
}
// When specifying array subroutine parameters, there is a second format where
// the sizes of the dimensions are not given explicitly, only the number of
// dimensions. This is where the ``sizeof`` operator is most useful. In these
// cases, `sizeof` is _not_ a compile-time constant.
def multi_dimensional_input(readonly array[int[32], #dim=3] my_array) {
uint[32] dimension_0 = sizeof(my_array, 0);
uint[32] dimension_1 = sizeof(my_array, 1);
uint[32] dimension_2 = sizeof(my_array, 2);
}