Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[rangeExpression] Clarification needed #469

Open
nelimee opened this issue May 1, 2023 · 0 comments
Open

[rangeExpression] Clarification needed #469

nelimee opened this issue May 1, 2023 · 0 comments
Labels
clarify specification Change text of spec, not (mainly) semantics of spec

Comments

@nelimee
Copy link
Contributor

nelimee commented May 1, 2023

The issue

The current grammar for the rangeExpression rule is:

rangeExpression: expression? COLON expression? (COLON expression)?;

This rule is only used in 2 rules:

  1. forStatement: FOR scalarType Identifier IN (setExpression | LBRACKET rangeExpression RBRACKET | Identifier) body=statementOrScope;
  2. indexOperator:
    LBRACKET
    (
    setExpression
    | (expression | rangeExpression) (COMMA (expression | rangeExpression))* COMMA?
    )
    RBRACKET;

The first rule, forStatement, requires both the first and last expression of the rangeExpression rule to be matched as explicitly written in the documentation:

- a range expression in square brackets of the form ``[start : (step :)? stop]``,
where ``step`` is equal to ``1`` if omitted. As in other range expressions,
the range is inclusive at both ends. Both ``start`` and ``stop`` must be
given. All three values must be of integer or unsigned-integer types. The
scalar type of elements in the resulting range expression is the same as the
type of result of the :ref:`implicit promotion <implicit-promotion-rules>`
between ``start`` and ``stop``. For example, if ``start`` is a ``uint[8]``
and ``stop`` is an ``int[16]``, the values to be assigned will all be of type
``int[16]``.

The second rule, indexOperator, is used in indexedIdentifier and the expression hierarchy. The only place I could find in the official documentation that mention this use of range is:

Ranges are written as ``a:b`` or
``a:c:b`` where ``a``, ``b``, and ``c`` are integers (signed or unsigned).
The range corresponds to the set :math:`\{a, a+c, a+2c, \dots, a+mc\}`
where :math:`m` is the largest integer such that :math:`a+mc\leq b` if
:math:`c>0` and :math:`a+mc\geq b` if :math:`c<0`. If :math:`a=b` then
the range corresponds to :math:`\{a\}`. Otherwise, the range is the
empty set. If :math:`c` is not given, it is assumed to be one, and
:math:`c` cannot be zero. Note the index sets can be defined by
variables whose values may only be known at run time.

and it also requires that both the first and last expressions are present.

This means that, if we follow the official documentation, the following OpenQASM 3.0 statements should be invalid

// Declaration of variable, this is a valid statement
array[int, 10] arr = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
// Invalid statements
arr[:1]; // {0, 1}
arr[3:]; // {3, 4, 5, 6, 7, 8, 9}
arr[:]; // {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
// /!\ Does not reverse the array like in Python.
arr[::-1]; // {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}

but all of them are accepted by the grammar for the moment.

I understand that this grammar rule mimics Python's indexing (or is inspired from it, the central position of the step argument being different from Python), and the parser code

def visitRangeExpression(self, ctx: qasm3Parser.RangeExpressionContext):
# start, end and step are all optional as in [:]
# It could be [start:end] or [start:step:end]
start = None
end = None
step = None
colons_seen = 0
for child in ctx.getChildren():
if isinstance(child, qasm3Parser.ExpressionContext):
expression = self.visit(child)
if colons_seen == 0:
start = expression
elif colons_seen == 1:
end = expression
else:
step = end
end = expression
elif child.getText() == ":":
colons_seen += 1
return ast.RangeDefinition(start=start, end=end, step=step)

seems to agree with the version presented in the grammar.

How to fix

If the grammar and the parser are right and indexing should work like in Python then:

  1. Change the official specification to reflect this.
  2. I expect the line for int i in [:20] to be invalid OpenQASM 3.0. If you agree, then something should be done to avoid such a line to be parsed correctly. This can be done directly in the grammar, but it might be more interesting to check in the parser.
  3. If I am wrong for 2. and for int i in [:20] should be valid, then the documentation should be improved to specifically address this construct and unambiguously define its meaning.

If the documentation is right, then directly modifying the grammar rule to

rangeExpression: expression COLON expression (COLON expression)?; 

or another equivalent rule and updating the AST typing would be the easiest path.

@jlapeyre jlapeyre added the clarify specification Change text of spec, not (mainly) semantics of spec label Jan 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clarify specification Change text of spec, not (mainly) semantics of spec
Projects
None yet
Development

No branches or pull requests

2 participants