For loop over inhomogeneous tuples #12

Closed
opened 2021-06-07 10:12:03 +08:00 by pca006132 · 13 comments

From ndscan/scan_runner.py:

Build kernel function that calls _kscan_param_values_chunk() and iterates over
the returned values, assigning them to the respective parameter stores and
calling _kscan_run_point() for each.

Currently, this can't be expressed as generic code, as there is no way to
express indexing or deconstructing a tuple of values of inhomogeneous types
without actually writing it out as an assignment from a tuple value.

This is one of the reason that requires code generation for ndscan. Maybe we can support for loops over inhomogeneous tuples by unrolling the loop and then do the type checking.

From [ndscan/scan_runner.py](https://github.com/OxfordIonTrapGroup/ndscan/blob/9d46a98df2abafa61640b6d8085a59491b240441/ndscan/experiment/scan_runner.py#L158-L164): > Build kernel function that calls _kscan_param_values_chunk() and iterates over > the returned values, assigning them to the respective parameter stores and > calling _kscan_run_point() for each. > > Currently, this can't be expressed as generic code, as there is no way to > express indexing or deconstructing a tuple of values of inhomogeneous types > without actually writing it out as an assignment from a tuple value. This is one of the reason that requires code generation for ndscan. Maybe we can support for loops over inhomogeneous tuples by unrolling the loop and then do the type checking.

Sounds good.

Sounds good.
Poster
Owner
Related: [inhomogeneous kernel lists #519](https://github.com/m-labs/artiq/issues/519)

D works this way (AliasSeq!() constructs a built-in tuple):

foreach (a; AliasSeq!(3, "foo", 42.0)) {
	writeln(a);
}

The loop body is effectively unrolled for this style of "static foreach", which worked out quite well, and I found quite easy to grasp/teach.

D works this way (`AliasSeq!()` constructs a built-in tuple): ```d foreach (a; AliasSeq!(3, "foo", 42.0)) { writeln(a); } ``` The loop body is effectively unrolled for this style of "static foreach", which worked out quite well, and I found quite easy to grasp/teach.

Perhaps the cleanest way would be to allow some sort of unroll loop annotation for integer-ranged loops that works unchanged in host Python, but leads to the loop variable being a compile-time constant in @kernel.

This could then be coupled with allowing compile-time constants as tuple indices.

Perhaps the cleanest way would be to allow some sort of `unroll` loop annotation for integer-ranged loops that works unchanged in host Python, but leads to the loop variable being a compile-time constant in @kernel. This could then be coupled with allowing compile-time constants as tuple indices.
Poster
Owner

Perhaps the cleanest way would be to allow some sort of unroll loop annotation for integer-ranged loops that works unchanged in host Python, but leads to the loop variable being a compile-time constant in @kernel.

This could then be coupled with allowing compile-time constants as tuple indices.

OK. It seems that python decorators (@something) cannot be used here, maybe we should use a comment? What about #artiq:unroll or something similar?

> Perhaps the cleanest way would be to allow some sort of `unroll` loop annotation for integer-ranged loops that works unchanged in host Python, but leads to the loop variable being a compile-time constant in @kernel. > > This could then be coupled with allowing compile-time constants as tuple indices. OK. It seems that python decorators (`@something`) cannot be used here, maybe we should use a comment? What about `#artiq:unroll` or something similar?

Put it on the iterator or test?

for i in unroll(range(12)):
  ...

while unroll(x < 1234):
  ...
  
for device in unroll((ttl0, ttl1, dds0, dds1)):
  ...

Put it on the iterator or test? ```python for i in unroll(range(12)): ... while unroll(x < 1234): ... for device in unroll((ttl0, ttl1, dds0, dds1)): ... ```

That being said, if we start doing pseudocomments for this sort of thing (e.g. #9 (comment)) then we probably want to consistently use pseudocomments.

That being said, if we start doing pseudocomments for this sort of thing (e.g. https://git.m-labs.hk/M-Labs/nac3-spec/issues/9#issuecomment-2105) then we probably want to consistently use pseudocomments.

What about #artiq:unroll or something similar?

It should be # nac3:unroll. nac3core should be usable outside ARTIQ.

> What about #artiq:unroll or something similar? It should be ``# nac3:unroll``. nac3core should be usable outside ARTIQ.
Poster
Owner

Put it on the iterator or test?

for i in unroll(range(12)):
  ...

while unroll(x < 1234):
  ...
  
for device in unroll((ttl0, ttl1, dds0, dds1)):
  ...

Do we have to support while loops? Also, I wonder if it would be complicated to write it as a function, as we could have cases like this:

a = unroll(range(12))
for i in a:
    pass

I think a pseudocomment would be simpler, and we could raise an error in case the loop cannot be unrolled statically, instead of throwing type errors.

> Put it on the iterator or test? > > ```python > for i in unroll(range(12)): > ... > > while unroll(x < 1234): > ... > > for device in unroll((ttl0, ttl1, dds0, dds1)): > ... > > ``` > Do we have to support while loops? Also, I wonder if it would be complicated to write it as a function, as we could have cases like this: ```python a = unroll(range(12)) for i in a: pass ``` I think a pseudocomment would be simpler, and we could raise an error in case the loop cannot be unrolled statically, instead of throwing type errors.

Ok, pseudocomment it is then.

Ok, pseudocomment it is then.

Do we have to support while loops?

Not necessarily, but it shouldn't be very complicated to support them I believe.

> Do we have to support while loops? Not necessarily, but it shouldn't be very complicated to support them I believe.
Poster
Owner

Do we have to support while loops?

Not necessarily, but it shouldn't be very complicated to support them I believe.

For example:

a = 0
while a < 10:
    if random() > 0.5:
        a += 1

This is just an example. I don't think we can fully unroll this kind of loops, and it would be hard to explain if the code is a bit more complicated or involves multiple variables. We can unroll for loops as long as the list is constant size or the iterator is known statically, which we should, and we could just raise an error if it isn't (with a clear error message that which iterator cannot be unrolled statically).

> > Do we have to support while loops? > > Not necessarily, but it shouldn't be very complicated to support them I believe. For example: ```python a = 0 while a < 10: if random() > 0.5: a += 1 ``` This is just an example. I don't think we can fully unroll this kind of loops, and it would be hard to explain if the code is a bit more complicated or involves multiple variables. We can unroll for loops as long as the list is constant size or the iterator is known statically, which we should, and we could just raise an error if it isn't (with a clear error message that which iterator cannot be unrolled statically).

Sure. I would only support the most simple cases, if anything. By "simple case" I mean a few arithmetic operations on the loop variable and maybe support related variables and tests. Anyway that is not important.

Sure. I would only support the most simple cases, if anything. By "simple case" I mean a few arithmetic operations on the loop variable and maybe support related variables and tests. Anyway that is not important.
pca006132 referenced this issue from a commit 2021-06-09 09:46:07 +08:00
Sign in to join this conversation.
No Label
No Milestone
No Assignees
3 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: M-Labs/nac3-spec#12
There is no content yet.