Skip to content

Commit 34e22db

Browse files
fedimserrht
authored andcommitted
Support sqrt(iSWAP) and Sycamore gates in Floquet calibration (quantumlib#4248)
Goal of this PR is that circuits having any of these 2-qubit gates (sqrt(iSWAP), Sycamore) can be calibrated on real hardware. In quantumlib#4164 I ensured that any FSim-compatible gate can be handled on compensation phase. But on characterization step we can support only these 2 gates, because only they are implemented in hardware (so far). For that: * Added method `try_convert_syc_or_sqrt_iswap_to_fsim` which is restriction of `try_convert_gate_to_fsim` on gates supported by hardware. * Used that method in `workflow.py` as gate translator everywhere where `try_convert_sqrt_iswap_to_fsim` was used. * Fixed a bug in `_merge_into_calibrations` so if there are calibrations for 2 different gates, it wouldn't fail with assertion error, but would append new calibration to the list of calibration. * Modified a test `test_run_zeta_chi_gamma_calibration_for_moments` so the circuit under test contains gates of 2 types.
1 parent 3179831 commit 34e22db

File tree

5 files changed

+85
-50
lines changed

5 files changed

+85
-50
lines changed

cirq-google/cirq_google/calibration/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
WITHOUT_CHI_FLOQUET_PHASED_FSIM_CHARACTERIZATION,
3636
merge_matching_results,
3737
try_convert_sqrt_iswap_to_fsim,
38+
try_convert_syc_or_sqrt_iswap_to_fsim,
3839
)
3940

4041
from cirq_google.calibration.workflow import (

cirq-google/cirq_google/calibration/phased_fsim.py

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import collections
1616
import dataclasses
1717
import functools
18+
import math
1819
import re
1920
from typing import (
2021
Any,
@@ -1016,35 +1017,12 @@ def try_convert_sqrt_iswap_to_fsim(gate: cirq.Gate) -> Optional[PhaseCalibratedF
10161017
either FSimGate, ISWapPowGate, PhasedFSimGate or PhasedISwapPowGate that is equivalent to
10171018
FSimGate(theta=±π/4, phi=0). None otherwise.
10181019
"""
1019-
if isinstance(gate, cirq.FSimGate):
1020-
if not np.isclose(gate.phi, 0.0):
1021-
return None
1022-
angle = gate.theta
1023-
elif isinstance(gate, cirq.ISwapPowGate):
1024-
angle = -gate.exponent * np.pi / 2
1025-
elif isinstance(gate, cirq.PhasedFSimGate):
1026-
if (
1027-
not np.isclose(gate.zeta, 0.0)
1028-
or not np.isclose(gate.chi, 0.0)
1029-
or not np.isclose(gate.gamma, 0.0)
1030-
or not np.isclose(gate.phi, 0.0)
1031-
):
1032-
return None
1033-
angle = gate.theta
1034-
elif isinstance(gate, cirq.PhasedISwapPowGate):
1035-
if not np.isclose(-gate.phase_exponent - 0.5, 0.0):
1036-
return None
1037-
angle = gate.exponent * np.pi / 2
1038-
else:
1020+
result = try_convert_gate_to_fsim(gate)
1021+
if result is None:
10391022
return None
1040-
1041-
angle_canonical = angle % (2 * np.pi)
1042-
1043-
if np.isclose(angle_canonical, np.pi / 4):
1044-
return PhaseCalibratedFSimGate(cirq.FSimGate(theta=np.pi / 4, phi=0.0), 0.0)
1045-
elif np.isclose(angle_canonical, 7 * np.pi / 4):
1046-
return PhaseCalibratedFSimGate(cirq.FSimGate(theta=np.pi / 4, phi=0.0), 0.5)
1047-
1023+
engine_gate = result.engine_gate
1024+
if math.isclose(engine_gate.theta, np.pi / 4) and math.isclose(engine_gate.phi, 0.0):
1025+
return result
10481026
return None
10491027

10501028

@@ -1097,3 +1075,28 @@ def try_convert_gate_to_fsim(gate: cirq.Gate) -> Optional[PhaseCalibratedFSimGat
10971075
phase_exponent = phase_exponent + 0.5
10981076
phase_exponent %= 1
10991077
return PhaseCalibratedFSimGate(cirq.FSimGate(theta=theta, phi=phi), phase_exponent)
1078+
1079+
1080+
def try_convert_syc_or_sqrt_iswap_to_fsim(
1081+
gate: cirq.Gate,
1082+
) -> Optional[PhaseCalibratedFSimGate]:
1083+
"""Converts a gate to equivalent PhaseCalibratedFSimGate if possible.
1084+
1085+
Args:
1086+
gate: Gate to convert.
1087+
1088+
Returns:
1089+
Equivalent PhaseCalibratedFSimGate if its `engine_gate` is Sycamore or inverse sqrt(iSWAP)
1090+
gate. Otherwise returns None.
1091+
"""
1092+
result = try_convert_gate_to_fsim(gate)
1093+
if result is None:
1094+
return None
1095+
engine_gate = result.engine_gate
1096+
if math.isclose(engine_gate.theta, np.pi / 2) and math.isclose(engine_gate.phi, np.pi / 6):
1097+
# Sycamore gate.
1098+
return result
1099+
if math.isclose(engine_gate.theta, np.pi / 4) and math.isclose(engine_gate.phi, 0.0):
1100+
# Inverse sqrt(iSWAP) gate.
1101+
return result
1102+
return None

cirq-google/cirq_google/calibration/phased_fsim_test.py

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
WITHOUT_CHI_FLOQUET_PHASED_FSIM_CHARACTERIZATION,
3838
merge_matching_results,
3939
try_convert_gate_to_fsim,
40+
try_convert_syc_or_sqrt_iswap_to_fsim,
4041
try_convert_sqrt_iswap_to_fsim,
4142
XEBPhasedFSimCalibrationRequest,
4243
XEBPhasedFSimCalibrationOptions,
@@ -767,7 +768,7 @@ def test_try_convert_sqrt_iswap_to_fsim_converts_correctly():
767768
expected, 0.0
768769
)
769770
assert (
770-
try_convert_sqrt_iswap_to_fsim(cirq.PhasedISwapPowGate(exponent=-0.5, phase_exponent=0.1))
771+
try_convert_sqrt_iswap_to_fsim(cirq.PhasedISwapPowGate(exponent=-0.6, phase_exponent=0.1))
771772
is None
772773
)
773774

@@ -949,11 +950,33 @@ def check(gate: cirq.Gate, expected: PhaseCalibratedFSimGate):
949950
assert try_convert_gate_to_fsim(cirq.CZPowGate(exponent=x)) is None
950951

951952

953+
def test_try_convert_syc_or_sqrt_iswap_to_fsim():
954+
def check_converts(gate: cirq.Gate):
955+
result = try_convert_syc_or_sqrt_iswap_to_fsim(gate)
956+
assert np.allclose(cirq.unitary(gate), cirq.unitary(result))
957+
958+
def check_none(gate: cirq.Gate):
959+
assert try_convert_syc_or_sqrt_iswap_to_fsim(gate) is None
960+
961+
check_converts(cirq_google.ops.SYC)
962+
check_converts(cirq.FSimGate(np.pi / 2, np.pi / 6))
963+
check_none(cirq.FSimGate(0, np.pi))
964+
check_converts(cirq.FSimGate(np.pi / 4, 0.0))
965+
check_none(cirq.FSimGate(0.2, 0.3))
966+
check_converts(cirq.ISwapPowGate(exponent=0.5))
967+
check_converts(cirq.ISwapPowGate(exponent=-0.5))
968+
check_none(cirq.ISwapPowGate(exponent=0.3))
969+
check_converts(cirq.PhasedFSimGate(theta=np.pi / 4, phi=0.0, chi=0.7))
970+
check_none(cirq.PhasedFSimGate(theta=0.3, phi=0.4))
971+
check_converts(cirq.PhasedISwapPowGate(exponent=0.5, phase_exponent=0.75))
972+
check_none(cirq.PhasedISwapPowGate(exponent=0.4, phase_exponent=0.75))
973+
check_none(cirq.ops.CZPowGate(exponent=1.0))
974+
check_none(cirq.CX)
975+
976+
952977
# Test that try_convert_gate_to_fsim is extension of try_convert_sqrt_iswap_to_fsim.
953978
# In other words, that both function return the same result for all gates on which
954979
# try_convert_sqrt_iswap_to_fsim is defined.
955-
# TODO: instead of having multiple gate translators, we should have one, the most general, and
956-
# restrict it to different gate sets.
957980
def test_gate_translators_are_consistent():
958981
def check(gate):
959982
result1 = try_convert_gate_to_fsim(gate)

cirq-google/cirq_google/calibration/workflow.py

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
THETA_ZETA_GAMMA_FLOQUET_PHASED_FSIM_CHARACTERIZATION,
4242
merge_matching_results,
4343
try_convert_gate_to_fsim,
44-
try_convert_sqrt_iswap_to_fsim,
44+
try_convert_syc_or_sqrt_iswap_to_fsim,
4545
PhasedFSimCalibrationOptions,
4646
RequestT,
4747
LocalXEBPhasedFSimCalibrationRequest,
@@ -73,7 +73,7 @@ def prepare_characterization_for_moment(
7373
*,
7474
gates_translator: Callable[
7575
[cirq.Gate], Optional[PhaseCalibratedFSimGate]
76-
] = try_convert_sqrt_iswap_to_fsim,
76+
] = try_convert_syc_or_sqrt_iswap_to_fsim,
7777
canonicalize_pairs: bool = False,
7878
sort_pairs: bool = False,
7979
) -> Optional[RequestT]:
@@ -116,7 +116,7 @@ def prepare_floquet_characterization_for_moment(
116116
options: FloquetPhasedFSimCalibrationOptions,
117117
gates_translator: Callable[
118118
[cirq.Gate], Optional[PhaseCalibratedFSimGate]
119-
] = try_convert_sqrt_iswap_to_fsim,
119+
] = try_convert_syc_or_sqrt_iswap_to_fsim,
120120
canonicalize_pairs: bool = False,
121121
sort_pairs: bool = False,
122122
) -> Optional[FloquetPhasedFSimCalibrationRequest]:
@@ -271,7 +271,7 @@ def prepare_characterization_for_moments(
271271
*,
272272
gates_translator: Callable[
273273
[cirq.Gate], Optional[PhaseCalibratedFSimGate]
274-
] = try_convert_sqrt_iswap_to_fsim,
274+
] = try_convert_syc_or_sqrt_iswap_to_fsim,
275275
merge_subsets: bool = True,
276276
initial: Optional[Sequence[RequestT]] = None,
277277
) -> Tuple[CircuitWithCalibration, List[RequestT]]:
@@ -345,7 +345,7 @@ def prepare_characterization_for_circuits_moments(
345345
*,
346346
gates_translator: Callable[
347347
[cirq.Gate], Optional[PhaseCalibratedFSimGate]
348-
] = try_convert_sqrt_iswap_to_fsim,
348+
] = try_convert_syc_or_sqrt_iswap_to_fsim,
349349
merge_subsets: bool = True,
350350
initial: Optional[Sequence[RequestT]] = None,
351351
) -> Tuple[List[CircuitWithCalibration], List[RequestT]]:
@@ -406,7 +406,7 @@ def prepare_floquet_characterization_for_moments(
406406
options: FloquetPhasedFSimCalibrationOptions = WITHOUT_CHI_FLOQUET_PHASED_FSIM_CHARACTERIZATION,
407407
gates_translator: Callable[
408408
[cirq.Gate], Optional[PhaseCalibratedFSimGate]
409-
] = try_convert_sqrt_iswap_to_fsim,
409+
] = try_convert_syc_or_sqrt_iswap_to_fsim,
410410
merge_subsets: bool = True,
411411
initial: Optional[Sequence[FloquetPhasedFSimCalibrationRequest]] = None,
412412
) -> Tuple[CircuitWithCalibration, List[FloquetPhasedFSimCalibrationRequest]]:
@@ -466,7 +466,7 @@ def prepare_characterization_for_operations(
466466
*,
467467
gates_translator: Callable[
468468
[cirq.Gate], Optional[PhaseCalibratedFSimGate]
469-
] = try_convert_sqrt_iswap_to_fsim,
469+
] = try_convert_syc_or_sqrt_iswap_to_fsim,
470470
permit_mixed_moments: bool = False,
471471
) -> List[RequestT]:
472472
"""Extracts a minimal set of characterization requests necessary to characterize all the
@@ -531,7 +531,7 @@ def prepare_floquet_characterization_for_operations(
531531
options: FloquetPhasedFSimCalibrationOptions = WITHOUT_CHI_FLOQUET_PHASED_FSIM_CHARACTERIZATION,
532532
gates_translator: Callable[
533533
[cirq.Gate], Optional[PhaseCalibratedFSimGate]
534-
] = try_convert_sqrt_iswap_to_fsim,
534+
] = try_convert_syc_or_sqrt_iswap_to_fsim,
535535
permit_mixed_moments: bool = False,
536536
) -> List[FloquetPhasedFSimCalibrationRequest]:
537537
"""Extracts a minimal set of Floquet characterization requests necessary to characterize all the
@@ -679,8 +679,12 @@ def _merge_into_calibrations(
679679
"""
680680
new_pairs = set(calibration.pairs)
681681
for index in pairs_map.values():
682-
assert calibration.gate == calibrations[index].gate
683-
assert calibration.options == calibrations[index].options
682+
can_merge = (
683+
calibration.gate == calibrations[index].gate
684+
and calibration.options == calibrations[index].options
685+
)
686+
if not can_merge:
687+
continue
684688
existing_pairs = calibrations[index].pairs
685689
if new_pairs.issubset(existing_pairs):
686690
return index
@@ -1057,6 +1061,7 @@ def from_characterization(
10571061
"""Creates an operation that compensates for zeta, chi and gamma angles of the supplied
10581062
gate and characterization.
10591063
1064+
Args:
10601065
Args:
10611066
qubits: Qubits that the gate should act on.
10621067
gate_calibration: Original, imperfect gate that is supposed to run on the hardware
@@ -1081,7 +1086,7 @@ def run_floquet_characterization_for_moments(
10811086
options: FloquetPhasedFSimCalibrationOptions = WITHOUT_CHI_FLOQUET_PHASED_FSIM_CHARACTERIZATION,
10821087
gates_translator: Callable[
10831088
[cirq.Gate], Optional[PhaseCalibratedFSimGate]
1084-
] = try_convert_sqrt_iswap_to_fsim,
1089+
] = try_convert_syc_or_sqrt_iswap_to_fsim,
10851090
merge_subsets: bool = True,
10861091
max_layers_per_request: int = 1,
10871092
progress_func: Optional[Callable[[int, int], None]] = None,
@@ -1147,7 +1152,7 @@ def run_zeta_chi_gamma_compensation_for_moments(
11471152
),
11481153
gates_translator: Callable[
11491154
[cirq.Gate], Optional[PhaseCalibratedFSimGate]
1150-
] = try_convert_sqrt_iswap_to_fsim,
1155+
] = try_convert_syc_or_sqrt_iswap_to_fsim,
11511156
merge_subsets: bool = True,
11521157
max_layers_per_request: int = 1,
11531158
progress_func: Optional[Callable[[int, int], None]] = None,

cirq-google/cirq_google/calibration/workflow_test.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@
4545
SQRT_ISWAP_INV_PARAMETERS = cirq_google.PhasedFSimCharacterization(
4646
theta=np.pi / 4, zeta=0.0, chi=0.0, gamma=0.0, phi=0.0
4747
)
48+
SYCAMORE_PARAMETERS = cirq_google.PhasedFSimCharacterization(
49+
theta=np.pi / 2, zeta=0.0, chi=0.0, gamma=0.0, phi=np.pi / 6
50+
)
4851
SQRT_ISWAP_GATE = cirq.FSimGate(7 * np.pi / 4, 0.0)
4952
SQRT_ISWAP_INV_GATE = cirq.FSimGate(np.pi / 4, 0.0)
5053

@@ -1462,19 +1465,19 @@ def test_run_zeta_chi_gamma_calibration_for_moments() -> None:
14621465
parameters_cd = cirq_google.PhasedFSimCharacterization(zeta=0.2, chi=0.3, gamma=0.4)
14631466

14641467
a, b, c, d = cirq.LineQubit.range(4)
1465-
engine_simulator = cirq_google.PhasedFSimEngineSimulator.create_from_dictionary_sqrt_iswap(
1468+
engine_simulator = cirq_google.PhasedFSimEngineSimulator.create_from_dictionary(
14661469
parameters={
1467-
(a, b): parameters_ab.merge_with(SQRT_ISWAP_INV_PARAMETERS),
1468-
(b, c): parameters_bc.merge_with(SQRT_ISWAP_INV_PARAMETERS),
1469-
(c, d): parameters_cd.merge_with(SQRT_ISWAP_INV_PARAMETERS),
1470+
(a, b): {SQRT_ISWAP_INV_GATE: parameters_ab.merge_with(SQRT_ISWAP_INV_PARAMETERS)},
1471+
(b, c): {cirq_google.ops.SYC: parameters_bc.merge_with(SYCAMORE_PARAMETERS)},
1472+
(c, d): {SQRT_ISWAP_INV_GATE: parameters_cd.merge_with(SQRT_ISWAP_INV_PARAMETERS)},
14701473
}
14711474
)
14721475

14731476
circuit = cirq.Circuit(
14741477
[
14751478
[cirq.X(a), cirq.Y(c)],
14761479
[SQRT_ISWAP_INV_GATE.on(a, b), SQRT_ISWAP_INV_GATE.on(c, d)],
1477-
[SQRT_ISWAP_INV_GATE.on(b, c)],
1480+
[cirq_google.ops.SYC.on(b, c)],
14781481
]
14791482
)
14801483

@@ -1490,7 +1493,7 @@ def test_run_zeta_chi_gamma_calibration_for_moments() -> None:
14901493
circuit,
14911494
engine_simulator,
14921495
processor_id=None,
1493-
gate_set=cirq_google.SQRT_ISWAP_GATESET,
1496+
gate_set=cirq_google.FSIM_GATESET,
14941497
options=options,
14951498
)
14961499

@@ -1505,7 +1508,7 @@ def test_run_zeta_chi_gamma_calibration_for_moments() -> None:
15051508
options=options,
15061509
),
15071510
cirq_google.PhasedFSimCalibrationResult(
1508-
gate=SQRT_ISWAP_INV_GATE, parameters={(b, c): parameters_bc}, options=options
1511+
gate=cirq_google.ops.SYC, parameters={(b, c): parameters_bc}, options=options
15091512
),
15101513
]
15111514
assert calibrated_circuit.moment_to_calibration == [None, None, 0, None, None, 1, None]

0 commit comments

Comments
 (0)