-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Conversation
fa125bb
to
07ba30a
Compare
Codecov ReportAttention: Patch coverage is
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. |
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 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.
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.
Please reduce the test duration to the order of seconds and make the axes argument in plot optional. Otherwise LGTM.
|
||
def plot_z_phase_calibration_result( | ||
before_after_df: 'pd.DataFrame', | ||
axes: np.ndarray[Sequence[Sequence['plt.Axes']], np.dtype[np.object_]], |
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.
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"]
.
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.
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_]], | ||
*, |
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.
@eliottrosenberg - Would it be useful to provide an optional pairs
argument if only specific qubit pairs are desired for plotting?
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 added that option
|
||
|
||
@pytest.mark.parametrize(['angles', 'error'], _create_tests(n=10, seed=32432432)) | ||
def test_calibrate_z_phases(angles, error): |
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 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
.
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.
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]) |
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.
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?
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 arrays are lists of floats/ints ... eveny when I explicitly passed np.array(..., dtype=float) I still got the same issue
@@ -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 |
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.
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
?
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.
are you sure?
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.
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)
@pavoljuhas ptal @eliottrosenberg I was not able to reproduce the warnings you recieved locally |
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.
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 |
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.
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, |
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.
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.
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.
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
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.
@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.
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.
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.
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
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, |
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.
Please make single process the default and split to 2 arguments as suggested above for z_phase_calibration_workflow.
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.
b241ec2
to
a372c8e
Compare
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.
LGTM with a few spelling suggestions. Thank you!
Co-authored-by: Pavol Juhas <[email protected]>
Co-authored-by: Pavol Juhas <[email protected]>
Co-authored-by: Pavol Juhas <[email protected]>
Co-authored-by: Pavol Juhas <[email protected]>
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
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
test notebook: https://colab.sandbox.google.com/drive/10gZ5dggYKH_xSsCJFpg__GakxvoaZDIi