-
Notifications
You must be signed in to change notification settings - Fork 129
Add Mirror RB experiment #842
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
base: main
Are you sure you want to change the base?
Conversation
qiskit_experiments/library/randomized_benchmarking/clifford_utils.py
Outdated
Show resolved
Hide resolved
qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py
Outdated
Show resolved
Hide resolved
qiskit_experiments/library/randomized_benchmarking/mirror_rb_analysis.py
Outdated
Show resolved
Hide resolved
qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py
Show resolved
Hide resolved
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.
Generally looks great, there are some small issues that needs addressing.
qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py
Outdated
Show resolved
Hide resolved
qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py
Outdated
Show resolved
Hide resolved
qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py
Outdated
Show resolved
Hide resolved
qiskit_experiments/library/randomized_benchmarking/mirror_rb_experiment.py
Outdated
Show resolved
Hide resolved
if self._inverting_pauli_layer: | ||
for circuit in circuits: | ||
target = circuit.metadata["target"] | ||
label = "".join(["X" if char == "1" else "I" for char in target]) |
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 have to admit I don't understand what's going on here.
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 comments, please let us know if it makes sense now
qiskit_experiments/library/randomized_benchmarking/clifford_utils.py
Outdated
Show resolved
Hide resolved
…ircuits, comment pauli label
illustrate, consider the two circuits below, both of which were generated in | ||
``pyGSTi``. The first circuit was transpiled in ``pyGSTi``, | ||
|
||
.. image:: pygsti-data-pygsti-transpiled-circ.png |
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.
Why this cannot be generated here? You have hidden cell option.
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.
pyGSTi is required to generate these circuits, and we don't want to require pyGSTi to accurately render the documentation.
""" | ||
|
||
# Backend must have a coupling map | ||
if not self._backend or not self._backend.configuration().coupling_map: |
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.
Hmm... I understand why we need this check here. Basically MirrorRB can target more than 2Q, then we should avoid applying 2Q gate to non-adjacent qubits otherwise extra SWAP is required.
On the other hand, the standard execution model of QE for now is
- define circuit in the virtual qubit domain
- call transpiler with initial layout, which is based on the experiment's physical qubits
- run circuit in the physical qubit domain (transpiled circuit) on the target backend.
and this experiment intentionally avoids step 1 due to above constraint. This probably motivate us to turn the backend
in the experiment class constructor into required (currently it's optional), and to deprecate another backend
argument in the BaseExperiment.run
method. This model indicates an experiment instance is always aware of the target backend, and we can reasonably generate circuits on top of some hardware architecture constraints -- as you are doing in this PR.
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 see, the reason why we added this check instead of making the backend required is because @chriseclectic and @coruscating had mentioned that backends aren't serializable, so it may be better to keep it optional and only check for it when the circuits are being generated. Considering these points, what would be the best option here?
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 lean toward having backend in the constructor as required because this benefits other experiments as well (e.g. T1 experiment needs to check timing constraints to build circuits). I think we should add special handling for backend in serialization/deserialization (I think it's enough to keep backend name instead of serialized object and ask user to set identical backend if the experiment is loaded instance).
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 discussed several potential plans for handling this in the meeting. @nkanazawa1989 are you okay with keeping the current implementation for this experiment and merging first, and then working on changing the implementation in a future PR?
# Backend must have a coupling map | ||
if not self._backend or not self._backend.configuration().coupling_map: | ||
raise QiskitError( | ||
"Must provide a backend with a coupling map or provide " |
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.
If a coupling map is not provided, you can generate all possible combination instead. Such data can be easily generated with itertools
.
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.
Done
|
||
# Store transpiled circuits in metadata | ||
for circ in transpiled: | ||
circ.metadata["transpiled_qiskit_circ"] = circ |
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 will break QPY serialization I guess unless you provide custom Json serializer.
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've moved this to a PR in the internal repository
full_sampling: bool = False, | ||
inverting_pauli_layer: bool = False, | ||
): | ||
"""Initialize a mirror randomized benchmarking experiment that uses |
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.
What is the benefit of this class for users? If this class is just for validation, you should extract the circuit generation logic and use it only in the unittest to compare the output circuits. If PyGSTi gives you something like x10 performance improvement, perhaps it's worth having it here, but not as a subclass. You can refer to the implementation of tomography module. There are several fitters available (numpy, scipy, cvxopt) but these are the single class and the internal logic is dynamically switched based on the analysis option. Something like this would work.
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 plan to make a separate PR for moving this class to the internal repository.
Would it be better to report error per layer instead of EPC? Especially since there will be non-Clifford and Clifford versions. |
@coruscating Yeah that would be more accurate |
I think this can be merged after addressing Naoki's comments and changing EPC to EPL. If issues come up later, those can be addressed in future PRs. |
The term "EPC" is currently used in standard and interleaved RB, so it would have to be replaced in those implementations too. Or maybe it would be better to replace "EPC" with "EPL" in the PR with universal-gate-set MRB. This PR implements MRB with circuits generated by the "old" sampling method which, to my knowledge, has only been implemented with Clifford gates. |
Agreed, let's leave it as EPC for this PR then. |
Assuming the branch
|
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 am very happy to see this PR as I think Mirror RB will a great asset to experiments!
My biggest concern with this PR is that MirrorRB, as implemented, doesn't let users specify the layers to use or the distribution over them, which is arguably the biggest selling point of mirror RB. Instead, the layers and the distribution are chosen by random_edgegrab_clifford_circuits. This assumption is baked into the API, so that generalizing MirrorRB to more diverse distributions would likely require a breaking change. To be clear, my main concern is the API; I think that using random edges is a very good thing to include in a first release, and also a very sensible default.
I suggest looking into whether the distribution itself could be an argument to the experiment, with random_edgegrab_clifford_circuits being one possible value. The distribution could be a callable returning layers, or something.
I have left a few other comments which, relative to the above, I view as being minor.
Among these comments, I'd just like to highlight that the experiment in a few places is described as being "more scalable" and also that "it can be used to detect crosstalk errors". I think the former statement is often worded to not give enough credit to other scalable characterization protocols that came before it, though I realize that (I think) the intent is to compare it only with standard randomized benchmarking using huge Cliffords. The latter statement, while true, I think is a bit narrow to be emphasized so heavily. Mirror RB at its core is for estimating fidelities marginalized over distributions of layers, and using several experiments to infer information about crosstalk is just one particular application of this ability.
@@ -30,6 +30,7 @@ class WebSite(Directive): | |||
.. ref_website:: qiskit-experiments, https://github.com/Qiskit/qiskit-experiments | |||
""" | |||
|
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 changes to this file look unnecessary; please revert them if so.
A new experiment class :class:`qiskit_experiments.library.MirrorRB` is | ||
introduced. This class implements mirror randomized benchmarking (RB), a version | ||
of RB that uses mirror circuits. It is more scalable than other RB protocols and | ||
can consequently be used to detect crosstalk errors. |
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 are many scalable RB protocols (direct fidelity estimation, cycle benchmarking, xeb, etc), so I think we sholud be a bit careful about the blanket statement "It is more scalable than other RB protocols". I suggest:
A new experiment class :class:`qiskit_experiments.library.MirrorRB` is
introduced. This class implements mirror randomized benchmarking (RB), which is a protocol
that measures the fidelity of user-defined ensembles of randomized mirror circuits.
@@ -41,8 +41,8 @@ | |||
"outputs": [], | |||
"source": [ | |||
"IBMQ.load_account()\n", |
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 changes to this file look unnecessary; please revert them if so.
@@ -40,8 +40,8 @@ | |||
"outputs": [], | |||
"source": [ | |||
"IBMQ.load_account()\n", |
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 changes to this file look unnecessary; please revert them if so.
Args: | ||
qubits: A list of physical qubits for the experiment. | ||
lengths: A list of RB sequences lengths. | ||
local_clifford: If True, begin the circuit with uniformly random 1-qubit |
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.
What value do the optional "local_clifford" and "pauli_randomize" bring to this experiment?
Mirror RB experiment | ||
-------------------- | ||
|
||
Mirror RB is a RB protocol that is more scalable to larger numbers of qubits, |
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 "more scalable" needs to be qualified a bit, and that crosstalk detection needs to be discussed as an application of the protocol rather than a central aspect. Indeed, standard randomized benchmarking in parallel can do some types of crosstalk detection.
Summary
Added mirror randomized benchmarking experiment and analysis classes
Details and comments
TODO
Accommodate mirror circuits of zero length