Add some utilities for T-rex error mitigation#8095
Conversation
obriente
left a comment
There was a problem hiding this comment.
Thanks for submitting! The code seems ok, but I'm worried about some forward-compatibility issues, as well as making the workflow as easy as possible to combine with other error mitigation techniques. Would defer to other people on the team whether this is a significant issue or something that we can deal with later.
| return sorted(all_qubits) | ||
|
|
||
|
|
||
| def _get_twirled_basis_gate(basis: cirq.Pauli, flip: bool) -> cirq.Gate: |
There was a problem hiding this comment.
The word 'twirl' is used for various things in the literature. Maybe it's better to call this 'trex-twirled' or 'readout-twirled'?
(Would defer to @zlatko-minev for an optimal name choice here.)
| return cirq.Rx(rads=-np.pi / 2) | ||
|
|
||
|
|
||
| def _build_twirled_pauli_circuits( |
There was a problem hiding this comment.
The name 'twirl' is used a lot in the literature, I'm not sure if 'twirled_pauli' is a good enough descriptor here? Would defer to @zlatko-minev for a decision here.
There was a problem hiding this comment.
Sure, I added trex prefix before twirled_pauli
| """Measures expectation values of Pauli strings using T-REX error mitigation. | ||
|
|
||
| Args: | ||
| circuits_to_pauli: Each object contains |
There was a problem hiding this comment.
How is this planned to work with the above code? Is the idea that this will call _build_twirled_pauli_circuits for each circuit in circuits_to_pauli, run this through sampler, and then process the result?
I suggest that we use the workflow that the user takes a circuit, builds the twirled circuits given this input, then runs each twirled circuit through a sampler themselves, and then we provide a function to compile the resulting list of results (or list of expectation values). This would be easier to integrate with other forms of error mitigation.
There was a problem hiding this comment.
Sure, I added a "generate_trex_and_readout_circuits" API which will return trex and readout circuits. I will add another method to compile the results.
| ) | ||
| twirl_circuits.append(twirled_circuit) | ||
|
|
||
| return twirl_circuits |
There was a problem hiding this comment.
@chriseclectic @eliottrosenberg - I think this is the best output one can give right now, but this requires the user keep track of twirl_choices themselves to know what to do with each circuit in twirl_circuits (which can be problematic, especially if we want to combine this with more error mitigation techniques).
Anyway, I guess the main question is - do you think that this will be forwards-compatible with any future changes to circuit data structures?
|
@obriente Would you be willing to act as reviewer for this PR? I mean, you basically have been already :-). Can we assign you to this PR? |
obriente
left a comment
There was a problem hiding this comment.
All of my comments were addressed, LGTM
mhucka
left a comment
There was a problem hiding this comment.
Spotted some possible minor issues.
| results: list[PauliStringMeasurementResult] | ||
|
|
||
|
|
||
| class TRexMetadata: |
There was a problem hiding this comment.
A couple of things:
-
I think this may need a
@dataclasses.dataclassdecorator. Without the decorator, Python will not create an__init__method. If the class has no__init__method, then attempting to instantiate it with arguments will fail at runtime with an error. -
There does not seem to be a unit test case that instantiates a
TRexMetadata. I think it would be worth adding one.
| return ops.Rx(rads=np.pi / 2) | ||
| elif basis == ops.Y and flip: | ||
| return ops.Rx(rads=-np.pi / 2) | ||
| else: |
There was a problem hiding this comment.
A branch for ops.I is missing, but it seems like there ought to be one.
|
|
||
| # The Pauli string that is being measured. | ||
| pauli_str: ops.PauliString | ||
| # A 2D boolean array of shape (num_readout_circuits, num_qubits) indicating |
There was a problem hiding this comment.
Should num_readout_circuits actually be num_twirls?
| return ops.Ry(rads=-np.pi / 2) | ||
| elif basis == ops.X and flip: | ||
| return ops.Ry(rads=np.pi / 2) | ||
| elif basis == ops.Y and not flip: | ||
| return ops.Rx(rads=np.pi / 2) | ||
| elif basis == ops.Y and flip: | ||
| return ops.Rx(rads=-np.pi / 2) |
There was a problem hiding this comment.
Elsewhere in this file, in the preexisting code, it uses the lowercase variants of the operators: ops.rx, ops.ry, etc. Would it make sense to use the lowercase variants here too, for consistency?
This PR introduces the initial building blocks and helper functions required to support T-REX error mitigation in
pauli expectation calculation.
The change includes:
Implement
_get_trex_twirled_basis_gateto fetch the appropriate rotation gates (Rx, Ry, X, I) based on the target Pauli basis and flip state.Implement
_generate_random_boolean_choicesto generate randomized 2D boolean arrays for twirling operations.Implement
_build_trex_twirled_pauli_circuitsto append the appropriate basis twirling gates and joint measurements to a base circuit.