-
Notifications
You must be signed in to change notification settings - Fork 982
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
Expand SWEEP_LIKE to work for {'t': [0, 1, 3]} #2786
Conversation
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.
Add test in sweepable_test.py
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.
Looks like you coded your own "cartesian-producter". Let's use itertools instead. Reference https://stackoverflow.com/a/533917/5716192.
From (https://stackoverflow.com/a/40623158/5716192). Let me know what you think. import itertools
def dict_product(dicts):
return (dict(zip(dicts, x)) for x in itertools.product(*dicts.values()))
print(list(dict_product({'t': [0, 2, 3]}))) # [{'t': 0}, {'t': 2}, {'t': 3}]
print(list(dict_product({'t': [0, 1], 's': [2, 3], 'r': 4}))) # Will not work for this call. Handle this case because '4' is not a list |
We recreated lots of packages by ourselves, I don't know what external packages we are supposed to use. |
@crystalzhaizhai Let's use |
It is more efficient. However, it looks like it won't work for our test case. And it also will break our previous cases. Because it only accepts lists as values. |
That code snippet was just an example of how we should use The |
cirq/study/sweepable.py
Outdated
@@ -55,7 +55,24 @@ def to_sweeps(sweepable: Sweepable) -> List[Sweep]: | |||
if isinstance(sweepable, Sweep): | |||
return [sweepable] | |||
if isinstance(sweepable, dict): | |||
return [_resolver_to_sweep(ParamResolver(cast(Dict, sweepable)))] | |||
expandsweepable = [cast(dict, {})] |
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.
Worth a comment to explain what case this code is handling?
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 "change dictionary of lists to list of dictionaries of single values using Cartesian product."
@@ -83,6 +83,18 @@ def test_to_sweeps_iterable_sweeps(): | |||
assert cirq.study.to_sweeps(sweeps) == sweeps | |||
|
|||
|
|||
def test_to_sweeps_dictionary_of_list(): | |||
assert cirq.study.to_sweeps({'t': [0, 2, 3]}) == \ |
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.
You can use parentheses to avoid the ""
assert (cirq.study.to_sweeps({'t': [0, 2, 3]}) ==
cirq.study.to_sweeps([{'t': 0}, {'t': 2}, {'t': 3}]))
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.
To keep consistent with previous test cases, I changed it to parentheses. However, check/format-incremental suggests something I feel a bit ugly. Is this what we want?
- assert (cirq.study.to_sweeps({'t': [0, 2, 3]}) ==
- cirq.study.to_sweeps([{'t': 0}, {'t': 2}, {'t': 3}]))
- assert (cirq.study.to_sweeps({'t': [0, 1], 's': [2, 3], 'r': 4}) ==
- cirq.study.to_sweeps([
- {'t': 0, 's': 2, 'r': 4},
- {'t': 0, 's': 3, 'r': 4},
- {'t': 1, 's': 2, 'r': 4},
- {'t': 1, 's': 3, 'r': 4},
- ]))
+ assert (cirq.study.to_sweeps({'t': [0, 2, 3]}) == cirq.study.to_sweeps([{
+ 't':
+ 0
+ }, {
+ 't':
+ 2
+ }, {
+ 't':
+ 3
+ }]))
+ assert (cirq.study.to_sweeps({
+ 't': [0, 1],
+ 's': [2, 3],
+ 'r': 4
+ }) == cirq.study.to_sweeps([
+ {
+ 't': 0,
+ 's': 2,
+ 'r': 4
+ },
+ {
+ 't': 0,
+ 's': 3,
+ 'r': 4
+ },
+ {
+ 't': 1,
+ 's': 2,
+ 'r': 4
+ },
+ {
+ 't': 1,
+ 's': 3,
+ 'r': 4
+ },
+ ]))
You can use parentheses to avoid the ""
assert (cirq.study.to_sweeps({'t': [0, 2, 3]}) == cirq.study.to_sweeps([{'t': 0}, {'t': 2}, {'t': 3}]))
def test_to_sweeps_dictionary_of_list(): | ||
assert cirq.study.to_sweeps({'t': [0, 2, 3]}) == \ | ||
cirq.study.to_sweeps([{'t': 0}, {'t': 2}, {'t': 3}]) | ||
assert cirq.study.to_sweeps({'t': [0, 1], 's': [2, 3], 'r': 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 think this case is quite ambiguous. You are assuming that this is a product, but it could be a zip, i.e.
cirq.study.to_sweeps([
{'t': 0, 's': 2, 'r': 4},
{'t': 1, 's': 3, 'r': 4},
])
At the very least, we need to document that multiple lists will be interpreted as a Product and not a Zip.
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.
Agree. That should be more clear. Do you mind pointing me to the location of the intended change?
cirq/study/sweepable.py
Outdated
for shortdict in expandsweepable: | ||
tempdict = shortdict.copy() | ||
tempdict[key] = item | ||
tempsweepable.append(cast(dict, tempdict)) |
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.
The above code is quite tricky to understand. It took me a while to figure out what this was doing, since it is repeatedly assigning the values. I would echo Victory's comment for using itertools if possible. This will also avoid recreating the entire dictionary every time there is a new list found as well.
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.
The above code is quite tricky to understand. It took me a while to figure out what this was doing, since it is repeatedly assigning the values. I would echo Victory's comment for using itertools if possible. This will also avoid recreating the entire dictionary every time there is a new list found as well.
I agree using itertools is easier to read. Do you have insights which approach would run faster? I tried to profile both methods, but the test case need to be large enough to make a difference.
cirq/study/sweepable.py
Outdated
@@ -55,7 +56,21 @@ def to_sweeps(sweepable: Sweepable) -> List[Sweep]: | |||
if isinstance(sweepable, Sweep): | |||
return [sweepable] | |||
if isinstance(sweepable, dict): | |||
return [_resolver_to_sweep(ParamResolver(cast(Dict, sweepable)))] | |||
""" |
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.
Remove this docstring and replace it with #
.
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.
LGTM
Fixes: #2698