-
Notifications
You must be signed in to change notification settings - Fork 6
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
Adding calibration parameters to qibocal #1021
Conversation
Which is the reason why you eventually decided to base this on https://github.com/qiboteam/qibocal/tree/0.2? (just to be aware) |
Given that this is required for 0.2 I thought that it could be more useful to start from the |
0ff0fe8
to
7edd452
Compare
I manage to restore the update for the parameters in calibration section for all protocols which have been ported to 0.2 in #990. As more protocols are added there I will update them also here. |
@andrea-pasquale actually I took a look, and to me, we could even merge this to #996, to avoid maintaining two branches, one on top of the other. Of course, I'd wait even for the others to take a look as well, since it is a good chance to do this with the isolated diff (rather than mixed together with the rest of the 0.2 update). |
@stavros11 as soon as you approve these changes we can decide where to merge this PR. Currently it is pointing to #990 but we could even merge it to #996. Let me know how you prefer to proceed. |
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 @andrea-pasquale. I had a quick look and some comments, but I would also like to test something on hardware before merging. Have you tried to do so and check if the updates are dumped properly?
Other than that, my main comment is that this is reintroducing some of the repetition we had in qibolab 0.1, as some values appear in both the calibration and the parameters file. For example frequency_01
will be the same as the drive config frequency, sweetspot
will be the same as the flux config offset, etc.. This is not necessarily bad, as it provides flexibility (eg. we may not want to operate the qubits at the sweetspot, etc.), however it will complicate the update process, both in the qibocal _update
rules and the manual copy-pasting (if fitting fails) since we will again need to put the same value in multiple places. Personally, I don't have a strong opinion against, just mentioning it for discussion.
@stavros11 as soon as you approve these changes we can decide where to merge this PR. Currently it is pointing to #990 but we could even merge it to #996. Let me know how you prefer to proceed.
Another option, since this seems to be more advanced than #996, is to merge directly to #990 and I will rebase #996 on top of it. Note that #996 will change completely anyway to follow the idea of qiboteam/qibolab#1061, so I would avoid putting anything on top of it right now.
class Model(BaseModel): | ||
"""Global model, holding common configurations.""" | ||
|
||
model_config = ConfigDict(extra="forbid") |
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 qibolab the base Model
is frozen. I guess here you are not doing this to make the updates easier, which makes sense to me.
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.
Indeed, after discussing with @alecandido we decided to not have a frozen
given that the update right now is quite cumbersome. If in qibolab we are able to find a suitable solution which is not too complicated we might go for a frozen model here as well.
src/qibocal/calibration/platform.py
Outdated
from pathlib import Path | ||
|
||
from qibolab import Platform, create_platform | ||
from qibolab._core.platform.load import PLATFORMS |
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.
Following up on this, I have not tested but it may actually be possible to get the path of a Platform
with the current public API using something like:
from qibolab import locate_platform
path = locate_platform(platform.name)
If this is sufficient, we won't need to release a new qibolab.
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.
locate_platform
seems to work correctly I didn't know about this function. Thanks!
src/qibocal/calibration/platform.py
Outdated
(Path(__file__).parent / "dummy.json").read_text() | ||
) | ||
else: | ||
path = Path(os.getenv(PLATFORMS)) / name |
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 at the functions in https://github.com/qiboteam/qibolab/blob/main/src/qibolab/_core/platform/load.py and in particuar: https://github.com/qiboteam/qibolab/blob/946a04f21f522cd05f898de91270153af7cdceff/src/qibolab/_core/platform/load.py#L25
I believe in qibolab we support storing multiple paths (with a separator) in the environment variable. I think this is not supported here, but again, I have not tested. This is also why it is safer to get the platform path using qibolab functions, instead of manually processing the environment variable here.
Nice catch @stavros11! Actually, I didn't investigate in depth the content of the calibration parameters, but just the structure of the implementation. EDIT: I take it back: the parameters in Qibolab are the operational ones, but they do not necessarily correspond to the physical values of the system (e.g. you can decide to operate a qubit out of its sweetspot, for some reason, or to apply a certain detuning) - I don't see them as redundant any longer. What do you think @stavros11? |
Thanks for the review @stavros11.
As you said, I know that in theory we are repeating some parameters, but the idea is that you don't necessarily want to operate the qubit at the "calibration parameters". You already mentioned the sweetspot, but also for the drive frequency some papers are showing that you might get better performances by not driving the qubit at its 0->1 frequency but a slight detuning might help, especially when using DRAG. See for example Sect. IV C 3 here. The same goes for the readout frequency. I know that up to know we were talking about frequencies in a very generic way but I believe that if we are able to distinguish between the physical frequencies (resonator frequency or qubit frequency) and the frequencies at which we operate our devices this could be beneficial. Moreover, we can come up with protocols in qibocal that are targerting only some of those.
Sure, originally I pointed to 0.2 since with #996 I was getting some import errors. |
from qibolab._core.identifier import QubitId, QubitPairId | ||
from qibolab._core.serialize import NdArray |
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.
Concerning the fact that it would be better to not import anything from _core
also here I am importing a few things. I remember that there were some discussions in the past about exposing QubitId
or QubitPairId
. In this particular case QubitPairId
is useful because I don't need to do anything to make sure that the pair is serialized correctly as a string. Eventually we could re-write some of these stuff in qibocal since we don't need to follow the exact serialization scheme of qibolab.
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 for pointing this out, I did not check in detail all changes.
I believe the initial idea for QubitId
and QubitPairId
was to not expose them from qibolab and therefore I had to redefine them in qibocal:
qibocal/src/qibocal/auto/operation.py
Lines 18 to 19 in d35ab6b
QubitId = Union[str, int] | |
QubitPairId = tuple[QubitId, QubitId] |
After merging this we will be following two different approaches, the (private) import here and the redefinition everywhere else in qibocal, which is not optimal. If the deserialization of QubitPairId
is really needed, we should consider if it's worth exposing it to public qibolab. I think qibocal will require a 0.2.1 anyway, in order to properly do parameter updates, so we could also include the QubitPairId
there.
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.
Yes, I agree with need a solution, though I'm not sure which is best. Maybe it's really correct to expose these identifiers, to avoid doubling the serialization support.
Instead, concerning releases:
- most likely it will be 0.2.2, because we may have postponed everything by one release, to have immediately the OPX1000 released (since already being used)
- @Edoardo-Pedicillo I may suggest renaming the milestone, since (in principle) we're not aiming to break Qibocal's interface (not that much, at least) and it will still be in the 0.1.x series (while introducing support for Qibolab 0.2)
- you may use
Qibocal - Qibolab 0.2
as temporary name to collect all these PRs, and then convert it to a milestone related to the actual targeted release in the 0.1.x series
- you may use
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 for the updates @andrea-pasquale. I also did a quick test and it seems to work, so it should be fine to merge in the 0.2 branch.
EDIT: I take it back: the parameters in Qibolab are the operational ones, but they do not necessarily correspond to the physical values of the system (e.g. you can decide to operate a qubit out of its sweetspot, for some reason, or to apply a certain detuning) - I don't see them as redundant any longer. What do you think @stavros11?
Indeed, these parameters are not strictly equivalent, we just happen to use the same values, that's why I said it's mostly for discussion.
However, in that case I would propose to go a step further and have different operations for updating each part. Qibocal's default _update
(and qq update
) should only update the calibration part and we provide a separate command or script that ports the changes to parameters (if the user wishes to do so). This new command will just copy some values from Calibration
to Parameters
(eg. frequency_01
will go to the drive configs, sweetspot to flux offsets, etc.) which is the default way we are operating right now.
Obviously this will add some overhead to usage (one more command), however I find it cleaner than the current approach, where we are duplicating the updates and essentially force using the qubits at their sweetspot.
EDIT: This suggestion is for another PR, not here. Actually #996 would be a good candidate to do this if you agree.
@stavros11 what you say makes sense, but I wonder whether it is really a convenient approach. In general, we may have some routines which are just characterizing the chip (finding things like I.e., the two-steps approach requires: parameters.json:
RX.frequency: ...
calibration.json:
RX.frequency: ...
frequency_01: ... otherwise it would be impossible to operate the qubit out of its frequency (or, conversely, to store its characterized frequency, if explicitly operated at a different one). |
Thanks for the proposal @stavros11. Eventually we could add a command to update the |
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 @andrea-pasquale , I have left some comments. Could you please have a look to the tests ?
# TODO: Add something related to resonator calibration | ||
|
||
|
||
class Qubit(Model): |
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.
Here some parameters are missing like Ec, even if it is equal to the anharmonicity in first approximation we can try to evaluate it (so not having it as property returning the anharmonicity) and Ej.
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.
Is it possible to measure the charging energy independently of the anharmonicity? (i.e. not measured as the frequencies' difference)
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.
There is already a parameter for Ec, it is called charging_energy
.
I could add also Ej
I decided not to included immediately since we have no protocols which can compute Ej
.
We can add some parameters later as soon as we have the corresponding protocols to evaluate them.
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.
There is already a parameter for Ec, it is called
charging_energy
.
Correct, but my understanding was that @Edoardo-Pedicillo acknowledged that, but he was proposing to have it an actual attribute (instead of a property) such that it can have a value that is different from -anharmonicity
.
And that's why I was asking whether it is possible to compute it independently.
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.
Is it possible to measure the charging energy independently of the anharmonicity? (i.e. not measured as the frequencies' difference)
Yes, from the qubit flux dependecy protocol (https://qibo.science/qibocal/stable/protocols/flux/single.html), in theory also
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.
Ok, you're right. The qubit frequency (ground->excited) is already functionally dependent on
Then I support your proposal: if we can measure both, we need two independent values, since they can be affected by approximations and the measurement process in different ways.
Then, if you only run a plain spectroscopy (identifying both transitions), you may compute the anharmonicity, but set also the charging energy as the best temporary estimate. Or avoid setting that at all, and do the fallback in the access process (if needed), to signal that the associated measurement has not been performed.
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.
Is it possible to measure the charging energy independently of the anharmonicity? (i.e. not measured as the frequencies' difference)
Yes, from the qubit flux dependecy protocol (https://qibo.science/qibocal/stable/protocols/flux/single.html), in theory also E J can be evaluated from there.
Yes, but actually given that the fit is already quite complicated
Regarding
return (1 + self.fidelity) / 2 | ||
|
||
|
||
class Coherence(Model): |
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.
Eventually I will take into consideration the error associated to this values. The same propagates for the other parameters.
I am not sure Coherence
should be separated from Qubit
, at the end these values are describing the qubit free evolution.
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.
Sure, I can add errors for these parameters. I can also move them inside the Qubit
class.
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 could even define a type for:
Measure = tuple[float, float]
"""Measured central value and associated uncertainty."""
(that's just a rough sketch, pick the name and description you find more suitable)
"""Readout information.""" | ||
coherence: Coherence = Field(default_factory=Coherence) | ||
"""Coherence times of the qubit.""" | ||
rb_fidelity: Optional[float] = None |
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.
We could have a Benchmarks
class containing all the fidelities/metrics (eventually also the gate fidelities coming from the interleaved RB), and drop TwoQubitCalibration
.
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.
Maybe I misunderstood: in which way is it different from a renaming proposal?
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.
Even if we create a Benchmark class containg all fidelities we will still need to have a TwoQubitCalibration
object given that at least there should a class for each qubit or qubit pair.
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.
Maybe I misunderstood: in which way is it different from a renaming proposal?
It was not proposing a renaming but a reordering, I was suggesting collecting all the fidelities together in a single class, since they are used for the same purpose, validation of the calibration.
Even if we create a Benchmark class containg all fidelities we will still need to have a
TwoQubitCalibration
object given that at least there should a class for each qubit or qubit pair.
Ok, I see your point, thanks.
There is not much that I can do about tests given that this PR is pointing at a branch where they are failing given that not all protocols have been updated to |
@andrea-pasquale you could test serialization and deserialization. E.g. making a closed loop, and checking the value is still consistent (that would be meaningful, because you would check for regressions in case of changes in some types). |
About this, there is also the option to skip tests of not updated routines in the |
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 @andrea-pasquale ! LGTM
Now that we arrived to 3 approvals (i.e. almost everyone saw the diff, and we have some consensus), shall we merge? |
This PR will restore the
characterization
section of the platform runcards that was removed during the update to0.2
by introducing acalibration.json
file.Checklist:
master
main