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

Create workflow for Z-phase calibration #6728

Merged
merged 27 commits into from
Nov 8, 2024

Conversation

NoureldinYosri
Copy link
Collaborator

@NoureldinYosri NoureldinYosri commented Sep 13, 2024

This calibration workflow is created for excitation preserving 2-qubit gates and assumes an error model that can be described with small random z-rotations

0: ───Rz(a)───two_qubit_gate───Rz(c)───
                │
1: ───Rz(b)───two_qubit_gate───Rz(d)───

for some small angles a, b, c, and d.


when the error model doesn't apply the workflow may give absured numbers (e.g. fidilities $\notin [0, 1]$). The fidilities can be slightly outside the $[0, 1]$ interval because it's a statistical estimate as can be seen in the following figure which compares the estimated fidelity of a CZ surrounded by random z rotations before and after calibration
image

test notebook: https://colab.sandbox.google.com/drive/10gZ5dggYKH_xSsCJFpg__GakxvoaZDIi

Copy link

codecov bot commented Sep 19, 2024

Codecov Report

Attention: Patch coverage is 98.15951% with 3 lines in your changes missing coverage. Please review.

Project coverage is 97.84%. Comparing base (2c914ce) to head (296922d).
Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
cirq-core/cirq/experiments/z_phase_calibration.py 96.61% 2 Missing ⚠️
cirq-core/cirq/experiments/two_qubit_xeb.py 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6728      +/-   ##
==========================================
- Coverage   97.85%   97.84%   -0.01%     
==========================================
  Files        1081     1083       +2     
  Lines       93370    93532     +162     
==========================================
+ Hits        91364    91519     +155     
- Misses       2006     2013       +7     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Collaborator

@eliottrosenberg eliottrosenberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really great, Nour!!

A few nits:
I think the default values in XEBPhasedFSimCharacterizationOptions should be

    characterize_theta=False,
    characterize_phi=False,
    zeta_default=0,
    chi_default=0,
    gamma_default=0

As written, the parameters like zeta_default are optional, but if you leave them as None, then it complains, e.g. ValueError: zeta_default was not set..

When running this, I get a lot of runtime warnings invalid value encountered in equal coming from cirq/value/value_equality_attr.py:82.

I tried running this twice on hardware. The first time, I got zeta=0.014562062933646333, chi=0.0651809408437691, gamma=-0.0799040390729371 and the second time, I got zeta=0.037173, chi=0.048721, gamma=-0.076402, which is basically consistent, but it would be good to quantify statistical uncertainty if that isn't too difficult.

A method for making a plot like the one that you posted would be really helpful: one that shows the fidelity vs depth for the original and reoptimized gates.

In order to use the results of this characterization tool, a simple transformer that replaces the original gates with the appropriate reoptimized gates could be helpful, but that can go in a separate PR.

Copy link
Collaborator

@pavoljuhas pavoljuhas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please reduce the test duration to the order of seconds and make the axes argument in plot optional. Otherwise LGTM.

cirq-core/cirq/experiments/z_phase_calibration.py Outdated Show resolved Hide resolved
cirq-core/cirq/experiments/xeb_fitting.py Outdated Show resolved Hide resolved

def plot_z_phase_calibration_result(
before_after_df: 'pd.DataFrame',
axes: np.ndarray[Sequence[Sequence['plt.Axes']], np.dtype[np.object_]],
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most other plotting functions have axes as an optional argument, which is created and returned if not provided.
Can we follow the same pattern here? Also please simplify the axes type to Sequence["plot.Axes"].

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also please simplify the axes type to Sequence["plot.Axes"]

when I do that I get

cirq-core/cirq/experiments/z_phase_calibration.py:250: error: Incompatible types in assignment (expression has type "ndarray[Any, dtype[Any]]", variable has type "Sequence[Axes] | None")  [assignment]
cirq-core/cirq/experiments/z_phase_calibration.py:251: error: Item "Sequence[Axes]" of "Sequence[Axes] | Any" has no attribute "flatten"  [union-attr]
cirq-core/cirq/experiments/z_phase_calibration.py:270: error: No return value expected  [return-value]

def plot_z_phase_calibration_result(
before_after_df: 'pd.DataFrame',
axes: np.ndarray[Sequence[Sequence['plt.Axes']], np.dtype[np.object_]],
*,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eliottrosenberg - Would it be useful to provide an optional pairs argument if only specific qubit pairs are desired for plotting?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added that option



@pytest.mark.parametrize(['angles', 'error'], _create_tests(n=10, seed=32432432))
def test_calibrate_z_phases(angles, error):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tests are very slow and take about 1 minute to run on my desktop with --numprocesses=2 (number of cores on GHA). They make up the bulk of the 20 slowest durations in this PRs CI at https://github.com/quantumlib/Cirq/actions/runs/11152830363/job/30999210792?pr=6728#step:7:507.

Please reduce the number and computational size of the tests so we don't add more than several seconds to the pytest time. The main purpose of unit tests is to exercise all code branches and check a few small and quick computations.
If you need to run larger tests, please move them to a separate test method decorated with @pytest.mark.slow.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

they should be faster now, ptal

_, axes = plt.subplots(1, 2)
plot_z_phase_calibration_result(before_after_df=df, axes=axes)

np.testing.assert_allclose(axes[0].lines[0].get_xdata().astype(float), [1, 2, 3])
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems the arrays passed to plotting have dtype=object, otherwise this should work without astype(float).
Is it feasible to convert to numerical arrays in or before the plotting code?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the arrays are lists of floats/ints ... eveny when I explicitly passed np.array(..., dtype=float) I still got the same issue

@CirqBot CirqBot added the size: L 250< lines changed <1000 label Oct 12, 2024
cirq-core/cirq/experiments/two_qubit_xeb.py Show resolved Hide resolved
cirq-core/cirq/experiments/two_qubit_xeb.py Show resolved Hide resolved
@@ -82,3 +82,6 @@
parallel_two_qubit_xeb as parallel_two_qubit_xeb,
run_rb_and_xeb as run_rb_and_xeb,
)


from cirq.experiments.z_phase_calibration import z_phase_calibration_workflow, calibrate_z_phases
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a little redundant to have both calibrate_z_phases and z_phase_calibration_workflow. Can we just have one thing with the functionality of z_phase_calibration_workflow?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are you sure?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On an unrelated note, please use the from somewhere import foo as foo so that the new names can be imported from cirq.experiments without raising mypy error. (Ref: #6717)

cirq-core/cirq/experiments/z_phase_calibration.py Outdated Show resolved Hide resolved
cirq-core/cirq/experiments/z_phase_calibration.py Outdated Show resolved Hide resolved
cirq-core/cirq/experiments/z_phase_calibration_test.py Outdated Show resolved Hide resolved
@NoureldinYosri
Copy link
Collaborator Author

@pavoljuhas ptal

@eliottrosenberg I was not able to reproduce the warnings you recieved locally

@NoureldinYosri NoureldinYosri requested review from pavoljuhas and eliottrosenberg and removed request for MichaelBroughton October 31, 2024 01:52
Copy link
Collaborator

@pavoljuhas pavoljuhas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor suggestions, otherwise LGTM.

@@ -82,3 +82,6 @@
parallel_two_qubit_xeb as parallel_two_qubit_xeb,
run_rb_and_xeb as run_rb_and_xeb,
)


from cirq.experiments.z_phase_calibration import z_phase_calibration_workflow, calibrate_z_phases
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On an unrelated note, please use the from somewhere import foo as foo so that the new names can be imported from cirq.experiments without raising mypy error. (Ref: #6717)

cycle_depths: Sequence[int] = tuple(np.arange(3, 100, 20)),
random_state: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None,
atol: float = 1e-3,
pool_or_num_workers: Optional[Union[int, 'multiprocessing.pool.Pool']] = None,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please make a single-process execution the default behavior of the pool argument.
Running via multiprocessing has previously caused unexpected problems in #6674.
It is better if users explicitly ask for multiprocessing so there is a better chance that
potential bugs appear then rather as a default behavior.

I would also recommend to split the pool_or_num_workers argument into two exclusive arguments, pool and num_workers: Optional[int].
The invocation via num_workers could then use a recursive call as

with multiprocessing.Pool(num_workers) as pool:
    return z_phase_calibration_workflow(sampler, ..., pool=pool)

which would be more robust for closing the pool in case of exception, you'd also won't need to track a local_pool flag.

Copy link
Collaborator Author

@NoureldinYosri NoureldinYosri Nov 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please make a single-process execution the default behavior of the pool argument

this was the initial behaviour but @eliottrosenberg requested the default be multiprocessing

I would also recommend to split the pool_or_num_workers argument into two exclusive arguments, pool and num_workers: Optional[int]

I condidered this but I thought the api would be a bit convoluted

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pavoljuhas I think that most users would use it with the default values without passing a parallel pool, and it is very slow that way.

Copy link
Collaborator

@pavoljuhas pavoljuhas Nov 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My concern is all other functions with pool-like argument interpret pool=None as run in series.
If reading z_phase_calibration_workflow(..., pool_or_num_workers=None) my expectation would be to have no pool and no workers, but in fact this starts a pool of ncpu size, which may cause memory problems on hosts with many CPUs.

Can we instead use some reasonable default, say 4, and not accept None, ie, make that argument of Union[int, 'multiprocessing.pool.Pool'] type?

Also renaming to num_workers_or_pool might give a better hint to pass integer and make distinction from pool-like arguments.

@NoureldinYosri

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

cycle_depths: Sequence[int] = tuple(np.arange(3, 100, 20)),
random_state: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None,
atol: float = 1e-3,
pool_or_num_workers: Optional[Union[int, 'multiprocessing.pool.Pool']] = None,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please make single process the default and split to 2 arguments as suggested above for z_phase_calibration_workflow.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator

@pavoljuhas pavoljuhas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with a few spelling suggestions. Thank you!

@NoureldinYosri NoureldinYosri enabled auto-merge (squash) November 7, 2024 23:56
@NoureldinYosri NoureldinYosri merged commit 59be462 into quantumlib:main Nov 8, 2024
37 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
size: L 250< lines changed <1000
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants