Skip to content
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

Slice platform #194

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft

Slice platform #194

wants to merge 4 commits into from

Conversation

alecandido
Copy link
Member

This is just a sketch of a proposal.

In this example, I'm taking the current platform for qw11q (containing qubits [D1, D2, D3, D4, D5]), and turning it into a platform with just two qubits ([D1, D3]), but otherwise identical.

This is my idea to provide "production" platforms without duplication.

The full-blown implementation would be a Qibolab function:

def slice_platform(name: str, inherit: str, qubits: set[QubitId], couplers: Optional[set[QubitId]] = None) -> Callable[[], Platform]:
    ...

such that you can use in place of the current implementation as

from pathlib import Path

from qibolab import slice_platform

NAME = Path(__file__).parent.name

create = slice_platform(NAME, "qw11q", {"D1, "D3"})

and that's it :)
(of course, you could even just type the NAME, and it reduces to just two lines)

@alecandido
Copy link
Member Author

Currently, I'm not aiming to merge this PR as it is, since it's mostly an example to discuss. However, whenever we agree about it, and the function will be made available, we could even enlarge qw11q, and use it to slice the production platform.

@stavros11
Copy link
Member

Thanks for the proposal @alecandido. The idea sounds good to me.

The only issue I see is that production platforms will have different names than the calibration ones, as we cannot have duplication. That would mean that the basic user that wants to execute circuits would have to know that they need to do

qibo.set_backend("qibolab", platform="qw11q_13")

instead of

qibo.set_backend("qibolab", platform="qw11q")

which is what one would naively expect, as it is using the same name as the slurm node.

An easy fix is to force using a different convention ("{platform_name}_cal" or "{platform_name}_dev") for calibration platforms that are merged to main and reserve the pure platform_name for production platforms. Then the people calibrating would have to use the longer name, but I would prefer moving the complexity to them, since they are the advanced users, and leave the simple name for basic circuit users.

We could even implement more automatic solutions where set_backend knows how to distinguish calibration from production platforms, but I would not go down that road, first because it would mean more maintenance from our side and second because there are cases where we are using circuits for calibration/characterization (such as RB).

@alecandido
Copy link
Member Author

That would mean that the basic user that wants to execute circuits would have to know that they need to do
[...]
which is what one would naively expect, as it is using the same name as the slurm node.

My understanding is that the "basic" user will not even use that name, since the cloud will expose chips with even further names (e.g. etna and so on).

An easy fix is to force using a different convention ("{platform_name}_cal" or "{platform_name}_dev") for calibration platforms [...]

Yes, that would have been even my proposal. We could use -dev, which is clear enough, or -base, to stress the idea that this is the one underlying the others with the same stem. But yes, any convention would work.

We could even implement more automatic solutions where set_backend knows how to distinguish calibration from production platforms, but I would not go down that road [...]

We could label all derived platforms, e.g. adding a derivation: bool = False parameter, and toggle it in the slice_platform function.
But yes, I would avoid that as well, and treat a sliced platform as a full-fledged platform with no distinction. This will generate fewer exceptional cases, and we'll apply the same operations to any kind of platform.

@andrea-pasquale
Copy link
Contributor

andrea-pasquale commented Oct 31, 2024

Thanks @alecandido, I tend to agree with @stavros11 in the sense that we should try to avoid to duplicate platforms.
I started to think about the problem and I have another proposal. A possible solution would be to include another attribute in the platform that we could call circuit_qubits, i.e. the quibits which are calibrated and can therefore be used to run circuits on hardware. Whenever the user execute a circuits the transpiler should be informed to use only those qubits, and perform all the necessary changes.

How do we select these qubits? If the user should select qubits based on physical calibration parameters such as T1, T2 or gate fidelity. We could let the create function load also the calibration parameters (which will be available after we merge #192) and we coud have a function select_calibrated_qubits to parse the qubits and keep those who are "well" calibrated. I image that this function will be platform agnostic. This function could also sort qubits such that if the user is planning to run only with one qubit the best calibrated qubit will be selected.

Here is a prototype.

from qibocal.calibration import Calibration, CALIBRATION
from qibolab import Platform

def select_calibrated_qubits(cal: Calibration) -> list[QubitId]:
    ....
    return ["D1", "D2"]

def create():
    ...
    cal = Calibration.load(FOLDER / CALIBRATION)
    circuit_qubits = select_calibrated_qubits(cal)
    ...
    return Platform.load(..., circuit_qubits=circuit_qubits)

I don't know how the transpiler should be modified exactly but at least in this way we can avoid platform duplication since people who are calibrating are going to play with the platform which will have access to all qubits (calibrated or not), while the more naive user, for example the cloud user, which will run circuits will be able to run only with calibrated qubits.

Thoughts?

@alecandido
Copy link
Member Author

alecandido commented Oct 31, 2024

Thanks @alecandido, I tend to agree with @stavros11 in the sense that we should try to avoid to duplicate platforms.

Well, it seemed to me that we had an agreement with @stavros11, and there is no duplication...

I started to think about the problem and I have another proposal. A possible solution would be to include another attribute in the platform that we could call circuit_qubits, i.e. the quibits which are calibrated and can therefore be used to run circuits on hardware. Whenever the user execute a circuits the transpiler should be informed to use only those qubits, and perform all the necessary changes.

How do we select these qubits? If the user should select qubits based on physical calibration parameters such as T1, T2 or gate fidelity. We could let the create function load also the calibration parameters (which will be available after we merge #192) and we coud have a function select_calibrated_qubits to parse the qubits and keep those who are "well" calibrated. I image that this function will be platform agnostic. This function could also sort qubits such that if the user is planning to run only with one qubit the best calibrated qubit will be selected.

Eventually, the only information that the user cares about is which qubits could be used, and then that's also the only information the transpiler cares about.
We can work towards a more complex transpiler, making use of calibration information to make informed choice, but:

  • the transpiler is already pretty complex (based on heuristics) and poorly maintained - adding information will make everything worse
  • even considering the former point, this is not a short-term project, so not a viable solution

Right now, qubits will have to be selected by the human operator calibrating the platform, deciding which one to expose. Or the human operator executing the circuit (but @scarrazza clarified this can't be the only option).

You can then turn your prototype in:

from qibolab import Platform

CIRCUIT_QUBITS = ["D1", "D2"]

def create():
    ...
    return Platform.load(..., circuit_qubits=CIRCUIT_QUBITS)

which is essentially the same of the proposal above. Only, it would require a change in the Platform object, making it more complex, without much advantage. That's why I excluded this option.

The derived platform won't be duplicated: it will mirror exactly the current one.
Moreover, the idea to expose the function is that this operation may even be used in other contexts.
But the input is the exact same of your prototype (if you agree with me that we can not rely on automated inspection of T1, T2, and fidelities - also because we do not care that much, @scarrazza pointed out that it is sufficient that they are connected).

@andrea-pasquale
Copy link
Contributor

Well, it seemed to me that we had an agreement with @stavros11, and there is no duplication...

There is no duplication in the sense that you have only one platform however, there is duplication in the sense that you will have two platform identifiers for the same platform since one will be used for production and the other one will be used for calibration.

Eventually, the only information that the user cares about is which qubits could be used, and then that's also the only information the transpiler cares about. We can work towards a more complex transpiler, making use of calibration information to make informed choice, but:

* the transpiler is already pretty complex (based on heuristics) and poorly maintained - adding information will make everything worse

* even considering the former point, this is not a short-term project, so not a viable solution

I'm not planning to have a complex calibration-aware mechanism. As in your case I want the transpiler to work only with select qubits, which will not be selected by the transpiler, but by the external function select_calibrated_qubits.

But the input is the exact same of your prototype (if you agree with me that we can not rely on automated inspection of T1, T2, and fidelities - also because we do not care that much, @scarrazza pointed out that it is sufficient that they are connected).

I would argue that we can rely on automated inspection, also because, people should not run on qubits where we did not run an RB previously at least once. Even if it is sufficient to have the qubits connected that would be easy to check even by looking at the fidelity because there will not be a fidelity, so the qubit will be excluded. Therefore a basic rule would be to check if the gate fidelity is larger than 90%.

Also I don't believe that adding the attribute calibrated_qubits will be too much complicated.

@alecandido
Copy link
Member Author

There is no duplication in the sense that you have only one platform however, there is duplication in the sense that you will have two platform identifiers for the same platform since one will be used for production and the other one will be used for calibration.

Well, not really. There are two platform identifiers, because you will load two different platform objects from them. That could be one - but since it is going to be used in two different ways, it even makes sense that the names are two, since in this way you can address the behavior you desire.

I'm not planning to have a complex calibration-aware mechanism. As in your case I want the transpiler to work only with select qubits, which will not be selected by the transpiler, but by the external function select_calibrated_qubits.

Ok, fine, so much the better :)

I would argue that we can rely on automated inspection, also because, people should not run on qubits where we did not run an RB previously at least once. Even if it is sufficient to have the qubits connected that would be easy to check even by looking at the fidelity because there will not be a fidelity, so the qubit will be excluded. Therefore a basic rule would be to check if the gate fidelity is larger than 90%.

Also I don't believe that adding the attribute calibrated_qubits will be too much complicated.

Well, an attribute on its own is never too complicated. But the point is that the attribute has to be handled, and to be handled in the transpiler it also has to be propagated.

If the transpiler would only receive the selected qubits, we could do this in the QibolabBackend, by exposing only those qubits to the backend user (including the transpiler).
But then, you would never be unable to run circuits on those platforms in the qubits which are not selected, unless you either:

  • compile them by yourself (but the compiler is not even exposed right now)
  • bypass somehow the further limitation introduced, resorting again to all the qubits

@andrea-pasquale
Copy link
Contributor

Well, an attribute on its own is never too complicated. But the point is that the attribute has to be handled, and to be handled in the transpiler it also has to be propagated.

I don't think the changes will be so complicated.

Well, an attribute on its own is never too complicated. But the point is that the attribute has to be handled, and to be handled in the transpiler it also has to be propagated.

If the transpiler would only receive the selected qubits, we could do this in the QibolabBackend, by exposing only those qubits to the backend user (including the transpiler). But then, you would never be unable to run circuits on those platforms in the qubits which are not selected, unless you either:

* compile them by yourself (but the compiler is not even exposed right now)

* bypass somehow the further limitation introduced, resorting again to all the qubits

Regarding this qibocal is already handling the compilation on its own to run circuits, I believe that we could update it to force it to run on any qubit.

@alecandido
Copy link
Member Author

So, I'm a huge fan of composition, and in principle the only drawback of your select_calibrated_qubits are the dependency on Qibocal, and necessity to be implemented reliably (which we're not yet sure what it means, and may depend on the use cases).

My proposal would then be to keep the extra names, slicing, but select_calibrated_qubits may be used (up to the platform author) as an input for that function.

What instead I disagree about is to replace the extra platform with an extra attribute, because this may generate more special cases, and cascade in further branching to be handled.

But we can have the best of both and combine them :)
Optionally combine is just the best, since you can still choose what you prefer :D

Regarding this qibocal is already handling the compilation on its own to run circuits, I believe that we could update it to force it to run on any qubit.

Well, that's not certainly the goal. And even if Qibocal is doing, if anyone else needs to do something similar, he should not be forced to pass through Qibocal because Qibolab is not enough. And it's not even the goal for Qibocal (if we can unlock compilation for Qibocal again, so much the better, no?)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants