Skip to content

Add the missing built-in constant-expression functions (popcount, rotl, rotr, mod, exp, log, pow, ceiling, floor) #390

Description

@TheGupta2012

Limitation

Table 2 — Built-in mathematical functions
lists the functions every OpenQASM 3 implementation must provide in constant expressions:

arccos, arcsin, arctan, ceiling, cos, exp, floor, log, mod, popcount,
pow, rotl, rotr, sin, sqrt, tan.

pyqasm's FUNCTION_MAP provides only abs, real, imag, sqrt, sin, cos, tan,
arccos, arcsin, arctan. Nine of the spec's functions are missing:
ceiling, floor, exp, log, mod, popcount, pow, rotl, rotr.

Example QASM failure

Every one of these is a valid constant expression per the spec:

import pyqasm

for decl in [
    "const uint c = popcount(37);",
    'const bit[8] c = rotl("00101010", 3);',
    'const bit[8] c = rotr("00101010", 3);',
    "const int c = mod(7, 2);",
    "const float[64] c = exp(1.0);",
    "const float[64] c = log(2.0);",
    "const int c = ceiling(1.2);",
    "const int c = floor(1.8);",
]:
    m = pyqasm.loads("OPENQASM 3.0;\n" + decl)
    m.validate()
ValidationError: Invalid initialization value for constant 'c'

They fail as gate arguments too, where sqrt already works:

OPENQASM 3.0;
include "stdgates.inc";
qubit[1] q;
rx(sqrt(2.0)) q[0];   // OK today
rx(exp(1.0)) q[0];    // ValidationError: Invalid parameter 'exp(1.0)' for gate 'rx'

The spec's own example under Built-in constant expression functions exercises most of them:

const float[64] f2 = 2.0 * exp(f1);
const int[8] i2 = pow(i1, u1);
const bit[8] b2 = rotl(b1, 3);

Change Requested

  1. Add ceiling, floor, exp, log, mod to FUNCTION_MAP with the spec's signatures.
  2. Add popcount, rotl, rotr, which operate on bit[n] and uint[n] and must preserve
    the input width.
  3. Add pow(a, b) as a function. Note the parser caveat below — this one is not purely a
    FUNCTION_MAP entry.
  4. Report an unknown function name and an arity or type mismatch as a ValidationError naming
    the function, rather than the current generic "Invalid initialization value" message,
    which gives the user no indication that the function was the problem.

Implementation Details

  • FUNCTION_MAP is in src/pyqasm/maps/expressions.py:196. Most additions are one line each:
    "exp": np.exp, "log": np.log, "ceiling": np.ceil, "floor": np.floor,
    "mod": np.mod.
  • popcount / rotl / rotr are defined on bit[n] and depend on a width-carrying bit
    representation — see the companion issue on bit[n] operators. Widths must be preserved:
    rotl(a, n) == rotr(a, -n), and the output width equals the input width.
  • pow has a known blocker. const int c = pow(2, 3); fails at parse time in
    openqasm3 1.0.1 because pow is also the gate-modifier keyword. Verify against the
    current upstream release and, if it still reproduces, open an issue on
    openqasm/openqasm and link it here; the pyqasm-side change can land independently for the
    other eight functions.
  • Spec overload resolution matters for the error messages: pow(int, uint) -> int is
    preferred over pow(float, float) -> float, which is preferred over the complex overload.
    exp and sqrt each have float -> float and complex -> complex forms.
  • Tests: tests/qasm3/test_expressions.py — one case per function covering a const
    declaration and a gate argument, plus arity and type-error cases.

Metadata

Metadata

Assignees

No one assigned

    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