-
Notifications
You must be signed in to change notification settings - Fork 25
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
Support for for-loops #24
Conversation
Codecov Report
@@ Coverage Diff @@
## master #24 +/- ##
==========================================
+ Coverage 96.78% 96.91% +0.13%
==========================================
Files 12 12
Lines 1615 1687 +72
==========================================
+ Hits 1563 1635 +72
Misses 52 52
Continue to review full report at Codecov.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is really cool @thisac! A couple of questions:
-
Does
for 3
iterate over [0, 1, 2] like Python, or [0, 1, 2, 3]? -
Can you do
for 3 -> m
, to havem
take the values 0, 1, 2 for each loop? -
It would be good to extend this to support not just passing the number of iterations, but providing the start, end, and step values. E.g.,
for 6, 20, 2 -> m
if self._infor: | ||
return |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be worth commenting to show what is happening here 🤔
It should iterate over [0, 1, 2], since it creates a
Yes, that's how it currently works.
Just implemented it with the syntax I updated the for-loop to support the same type of lists as the modes:
Also, any type of array will currently be considered a list, by flattening it before attempting to extract a value from it. So this should work in the context above as well:
|
Just curious about the philosophy for the chosen semantics here, as I found both Is this something that is forced by our choice of lexer/parser? Historical note: originally, blackbird was meant to be kept as close to "python" as possible, since the way a user declares their program in SF is essentially also "blackbird code" (with some small, unavoidable, modifications between "standalone blackbird" and "python-embedded blackbird"). Why would we want to do that here, where---at least to my naive eye---it doesn't seem necessary to depart from python style? |
@co9olguy There's no particular reason for choosing this style at all. I just played around with different semantics during the hackathon, but I could easily change it to be more python-like if that's preferred. 🙂 I chose to go with this since I thought it looked nice, and vaguely pythonic, while still following the style that I thought Blackbird had (e.g. few |
I'm in favour of making the syntax more Pythonic, with the caveat that Python doesn't actually have a native Implementing a native We could:
I quite like the second option. That being said, I do quite like @thisac's chosen syntax, it 'looks cool' 😆 |
[ch260] |
@josh146 @co9olguy I've changed the syntax for the for-loops to be more python-like. E.g. for int m in [2, 7, 3]
MeasureFock() | m to apply the operation to modes 2, 7 and 3, or par array phases =
{phase_0}
{phase_1}
{phase_2}
{phase_3}
{phase_4}
for int m in 0:5:1
MZgate(phases[m], phases[m+1]) | [m, m+1] to apply the MZgate with indexing from the phases list for the range 0:5:1 = [0, 1, 2, 3, 4]. I also added some tests and fixed some issues that I found along the way. 🙂 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking great @thisac! My main question was with respect to indexing of different shaped arrays, but apart from that it's looking good
def test_var_idx_in_modes(self, parse_input_mocked_metadata): | ||
"""Test that array indexing works inside modes""" | ||
bb = parse_input_mocked_metadata( | ||
"int array vars =\n\t1, 2\n\nMZgate(0, 1) | [vars[0], vars[1]]" | ||
) | ||
assert bb.operations == [ | ||
{'op': 'MZgate', 'args': [0, 1], 'kwargs': {}, 'modes': [1, 2]} | ||
] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test tests the case
int array vars =
1, 2
Is it worth also testing the case
int array vars =
1
2
(does this affect how you index?)
What about something like
int array vars =
1, 2
3, 4
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I deliberately made the arrays always behave as flat, in the sense that you can write them (and store them) as nested numpy-arrays but they will behave as flat with regards to indexing. So your examples above would basically behave the same only with the last one having two more elements.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought it looked nice to be able to list parameters vertically rather than horizontally,
par array phases =
{phase_0}
{phase_1}
{phase_2}
{phase_3}
{phase_4}
and vice versa with regards to values.
int array vars =
1, 2, 3, 4, 5, 42, 6
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
with pytest.raises(ValueError, match="invalid value"): | ||
bb = parse_input_mocked_metadata( | ||
"for int m in [1, 4.2, 9]\n\tMZgate(0, 1) | [0, 1]" | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great tests! Might also be worth testing
-
Indexing different shaped arrays (e.g., column vectors, matrices)
-
The case where stepsize is ignored, if this is allowed (wasn't sure based on the tests above)
-
Having expressions in the for loop syntax?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added tests for everything you mentioned. Realised that
int array vars =
1, 2
3, 4
works, while
int array vars =
1, 2
3
does not; but I think this is a minor issue and can be looked into closer if/when we decide to rework the BB array type to e.g. include 2d indexes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that should actually be fine, I'm not sure
int array vars =
1, 2
3
is intended to/should be allowed. Since this corresponds to a 'ragged' numpy array
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔥
Something that just crossed my mind --- we will need to update the documentation, and especially the In particular, to ensure that any deviations from Python are clearly laid out, such as flat indexing and for loops. |
Context: Currently Blackbird doesn't support for-loops and thus cannot iterate through lists of statements. This would be useful when having many similar statements.
Description: Support for parsing for-loops are added to Blackbird. The user can write e.g.:
to apply the operation to modes 2, 7 and 3, or
to apply the
MZgate
with indexing from thephases
list for the range0:5:1 = [0, 1, 2, 3, 4]
Other additions:
MZgate(list[2], list[0]) | [list[3],list[1]])
)phases[-3 + 2*2]
).