-
Notifications
You must be signed in to change notification settings - Fork 61
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
Updating GST to accept parameterised gates #1534
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #1534 +/- ##
=======================================
Coverage 99.68% 99.69%
=======================================
Files 80 80
Lines 11606 11613 +7
=======================================
+ Hits 11570 11577 +7
Misses 36 36
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
I am no expert of tomography, but exactly what do you mean by "tomography of a parametrized gate"? I mean, I presume you are thinking of: fixing the set of parameters and performing the tomography for that specific parameter choice. So it's not really a parametrized gate anymore. |
@BrunoLiegiBastonLiegi the problem I believe @mho291 is trying to address should not be theoretical, but rather technical. Cf. #1502 So, you're right that once the parameters are fixed, the gate is completely analogous to any other fixed one. But from the point of view of Qibo is still holding some parameters in an attribute. Thus, it's parameterized in that sense... |
Yeah, that I understand. This is a limitation imposed by the design choice (which was mine) of having only the class reference of gates passed rather than the actual instance. Hence: gate_set = [gates.X, gates.Y, gates.Z] rather than: gate_set = [gates.X(0), gates.Y(0), gates.Z(0)] The rationale behind this choice is that I honestly find misleading making the user pass a gate built on a qubit that is completely ignored by the GST in practice. Therefore, I know that this choice for instance limits the applicability of GST to parametrized gates, but is that really limiting some relevant set up? (This I am actually asking because I am not sure) In any case, apart from the philosophical motivation, I would rather suggest to have a separate GST(gate_set=[gates.RX, gates.Y, gates.U3], ..., gate_parameters=[rx_param, u3_params], ...) Or, alternatively, to pass the parametrized gates as a tuple:
|
Thanks @BrunoLiegiBastonLiegi and @alecandido. I guess the most straightforward reason to passing in a gate with parameters is so that the user does not need to transpile it to the standard gates. Will it be odd if we passed the entire gate but not use the qubit parameter, for e.g. Following the GST wishlist here, we might want to consider adding a feature that allows the user to specify which qubit to use and gates to use for state preparation & measurements, so that GST can be used on a device that supports verbatim compilation, like the Amazon Braket devices. It's more complicated than adding I've been doing GST with verbatim compilation on IQM Garnet recently so I have some gates that we can use for state preparation and measurements. There, I extracted the qubit information and used it for state preparation and measurements. But maybe let's leave that for a later task? |
In case, I would explore the option of using some clearly invalid value as a placeholder. More in details, not to check for this value (and just ignore it, as you would do anyhow), but rather to systematically use that to document the GST usage. The best one would be This is just to make it clear that this value is completely irrelevant (which makes explicit that the interface would be better without, but hiding it is just worse).
Definitely, let's keep for a separate task. The one in this PR is a patch, to allow working with something that before was not accepted (unexpectedly, perhaps). |
Thanks @alecandido . To carry on the discussion further, what might be the best way forward? I see two possible routes we can take:
Thanks a lot! Enjoy the weekends! |
@mho291 in case of doubt, do less (per PR). So, 2. is definitely better than 1.. @BrunoLiegiBastonLiegi's proposal was to do even less, not more (i.e. to avoid instances, in order to avoid the qubit specification). Concerning the alternative of doing more or less, the answer is less - and then move to further PRs.
Sorry for the late reply. I actually enjoyed it :P |
Thanks @alecandido , let me do it like how @BrunoLiegiBastonLiegi suggested, to incorporate the gate parameters: Glad you enjoyed the weekends! ;) |
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.
In general I still struggle to find a strong motivation for this, as it would make more sense to me to decompose your parametrized (fixed) gate in actual non parametrized ones, which will compose your gate set for GST then.
In any case, even though the (gate, params)
approach is probably not the cleanest, it should be fine for the moment.
Thanks @BrunoLiegiBastonLiegi for the comments.
True, I do see your point of view. However, if I wanted to quickly do GST for parameterised gates without the decomposition, then we'll probably need this small functionality. Correct me if I'm wrong: I have the impression that since Anyway, back to the PR, when I was constructing the From an end-user perspective, the most convenient way is to dump the entire gate and its parameters, including qubit specifications, into the |
Yeah, fair enough, it's surely faster to just allow for passing the parametrized gate here, rather than manually decomposing
Yes and now, because if I remember correctly our
I understand your wish of standardizing the inputs, but personally I am not a fan of making the user specify a non parametrized gate as (gate, []) everytime. Say for instance, that I want to run GST on GST(gate_set=[(X, []), (Y, []), (Z, [])]) not the best in my opinion. We could actually leverage the asimettry, instead, and infer from the presence of a tuple the presence of a parametrized gate. |
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.
Firstly, thanks @mho291 for the work! It sounds in general good to me.
About input parameters, I also think as @BrunoLiegiBastonLiegi a good solution for now would be to pass parametrised gates as tuples and non-parametrised gates as single elements in the gate_set
list. Another possibility would be to re-discuss how a gate is defined, and if we really need it to depend on a specific qubit number.
Anyway, this would be a way bigger discussion and I don't think this PR is the right place where to do it.
I left a couple of comments more and I would reccomend addressing the last comments from @BrunoLiegiBastonLiegi.
Thanks again :)
Thanks @MatteoRobbiati and @BrunoLiegiBastonLiegi . Yes, I have coded it to go with @BrunoLiegiBastonLiegi 's suggestion: If it's a parameterised gate, put it in a tuple. Then inside GST, check if it's a tuple, then access the parameters. I've done this: for gate in gate_set:
if gate is not None:
if isinstance(gate, tuple):
init_args = signature(gate[0]).parameters
params = gate[1]
gate_class = gate[0]
else:
init_args = signature(gate).parameters
params = []
gate_class = gate
angle_names = [name for name in init_args if name in {"theta", "phi", "lam"}]
angle_values = {}
for name, value in zip(angle_names, params):
angle_values[name] = value
if "q" in init_args:
nqubits = 1
elif "q0" in init_args and "q1" in init_args and "q2" not in init_args:
nqubits = 2
else:
raise_error(
RuntimeError,
f"Gate {gate} is not supported for `GST`, only 1- and 2-qubits gates are supported.",
)
gate = gate_class(*range(nqubits), **angle_values) It worked locally but the Pytests seemed to fail with error message These TypeErrors occur for =========================================================================================== short test summary info ===========================================================================================
FAILED test_tomography_gate_set_tomography.py::test_GST[numpy-False-target_gates0] - TypeError: (<class 'qibo.gates.gates.RX'>, [0.7853981633974483]) is not a callable object
FAILED test_tomography_gate_set_tomography.py::test_GST[numpy-True-target_gates0] - TypeError: (<class 'qibo.gates.gates.RX'>, [0.7853981633974483]) is not a callable object
FAILED test_tomography_gate_set_tomography.py::test_GST[qibojit-numba-False-target_gates0] - TypeError: (<class 'qibo.gates.gates.RX'>, [0.7853981633974483]) is not a callable object
FAILED test_tomography_gate_set_tomography.py::test_GST[qibojit-numba-True-target_gates0] - TypeError: (<class 'qibo.gates.gates.RX'>, [0.7853981633974483]) is not a callable object Later I checked with this code which also seems to fail due to the TypeError. I've confirmed that both the pasted code and the one in the link function the same. Oddly, the tests here are passing. Should I be concerned that tests on my local machine are failing? Thank you! |
Not sure, can you post the complete traceback of your local error? Silly question, you have installed this branch and not the qibo main, right? |
Not silly at all! It my oversight that I did |
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.
Thanks @mho291, looks good, just some minor final suggestions.
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.
Thanks! I would ask you to implement two more minor suggestions, but LGTM.
Co-authored-by: Matteo Robbiati <[email protected]>
Co-authored-by: Matteo Robbiati <[email protected]>
Checklist: