Skip to content

Commit bc76660

Browse files
Add serialization support to more gates (#6479)
This PR adds serializatoin support to - IdentityGate => fixes #4833 - HPowGate => allows sending circuits with cirq.H to backend - changes the handling of SingleQubitCliffordGate from automatic conversion to PhasedXZGate to have its own proto (originally proposed in #6418)
1 parent 4513892 commit bc76660

13 files changed

+338
-65
lines changed

cirq-core/cirq/testing/__init__.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,12 @@
6969

7070
from cirq.testing.equivalent_repr_eval import assert_equivalent_repr
7171

72-
from cirq.testing.gate_features import SingleQubitGate, TwoQubitGate, ThreeQubitGate
72+
from cirq.testing.gate_features import (
73+
SingleQubitGate,
74+
TwoQubitGate,
75+
ThreeQubitGate,
76+
DoesNotSupportSerializationGate,
77+
)
7378

7479
from cirq.testing.json import assert_json_roundtrip_works
7580

cirq-core/cirq/testing/gate_features.py

+10
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,13 @@ class ThreeQubitGate(raw_types.Gate):
3636

3737
def _num_qubits_(self) -> int:
3838
return 3
39+
40+
41+
class DoesNotSupportSerializationGate(raw_types.Gate):
42+
"""A gate that can't be serialized."""
43+
44+
def __init__(self, n_qubits: int = 1):
45+
self.n_qubits = n_qubits
46+
47+
def _num_qubits_(self) -> int:
48+
return self.n_qubits

cirq-google/cirq_google/api/v2/program.proto

+23
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,9 @@ message Operation {
209209
WaitGate waitgate = 16;
210210
InternalGate internalgate = 17;
211211
CouplerPulseGate couplerpulsegate = 18;
212+
IdentityGate identitygate = 19;
213+
HPowGate hpowgate = 20;
214+
SingleQubitCliffordGate singlequbitcliffordgate = 21;
212215
}
213216

214217
// Map from the argument name to the Argument needed to fully specify
@@ -434,4 +437,24 @@ message CouplerPulseGate{
434437
optional FloatArg coupling_mhz = 4;
435438
optional FloatArg q0_detune_mhz = 5;
436439
optional FloatArg q1_detune_mhz = 6;
440+
}
441+
442+
message CliffordTableau {
443+
optional int32 num_qubits = 1; // Number of qubits the CliffordTableau acts on.
444+
optional int32 initial_state = 2; // The initial state.
445+
repeated bool rs = 3; // A flattened version of the `rs` array.
446+
repeated bool xs = 4; // A flattened version of the `xs` array.
447+
repeated bool zs = 5; // A flattened version of the `zs` array.
448+
}
449+
450+
message SingleQubitCliffordGate {
451+
CliffordTableau tableau = 1;
452+
}
453+
454+
message IdentityGate {
455+
repeated uint32 qid_shape = 1;
456+
}
457+
458+
message HPowGate {
459+
FloatArg exponent = 1;
437460
}

cirq-google/cirq_google/api/v2/program_pb2.py

+56-48
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cirq-google/cirq_google/api/v2/program_pb2.pyi

+105-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cirq-google/cirq_google/devices/grid_device_test.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,9 @@ def test_grid_device_validate_operations_negative():
387387
device.validate_operation(cirq.CZ(q00, q10))
388388

389389
with pytest.raises(ValueError, match='gate which is not supported'):
390-
device.validate_operation(cirq.H(device_info.grid_qubits[0]))
390+
device.validate_operation(
391+
cirq.testing.DoesNotSupportSerializationGate()(device_info.grid_qubits[0])
392+
)
391393

392394

393395
@pytest.mark.parametrize(

cirq-google/cirq_google/engine/engine_processor_test.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,9 @@ def test_get_device():
288288
with pytest.raises(ValueError):
289289
device.validate_operation(cirq.X(cirq.GridQubit(1, 2)))
290290
with pytest.raises(ValueError):
291-
device.validate_operation(cirq.H(cirq.GridQubit(0, 0)))
291+
device.validate_operation(
292+
cirq.testing.DoesNotSupportSerializationGate()(cirq.GridQubit(0, 0))
293+
)
292294
with pytest.raises(ValueError):
293295
device.validate_operation(cirq.CZ(cirq.GridQubit(1, 1), cirq.GridQubit(2, 2)))
294296

cirq-google/cirq_google/engine/engine_test.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -824,6 +824,8 @@ def test_get_engine_device(get_processor):
824824
with pytest.raises(ValueError):
825825
device.validate_operation(cirq.X(cirq.GridQubit(1, 2)))
826826
with pytest.raises(ValueError):
827-
device.validate_operation(cirq.H(cirq.GridQubit(0, 0)))
827+
device.validate_operation(
828+
cirq.testing.DoesNotSupportSerializationGate()(cirq.GridQubit(0, 0))
829+
)
828830
with pytest.raises(ValueError):
829831
device.validate_operation(cirq.CZ(cirq.GridQubit(1, 1), cirq.GridQubit(2, 2)))

cirq-google/cirq_google/engine/virtual_engine_factory_test.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ def _test_processor(processor: cg.engine.abstract_processor.AbstractProcessor):
3535
circuit = cirq.Circuit(cirq.X(bad_qubit), cirq.measure(bad_qubit))
3636
with pytest.raises(ValueError, match='Qubit not on device'):
3737
_ = processor.run(circuit, repetitions=100)
38-
circuit = cirq.Circuit(cirq.H(good_qubit), cirq.measure(good_qubit))
38+
circuit = cirq.Circuit(
39+
cirq.testing.DoesNotSupportSerializationGate()(good_qubit), cirq.measure(good_qubit)
40+
)
3941
with pytest.raises(ValueError, match='Cannot serialize op'):
4042
_ = processor.run(circuit, repetitions=100)
4143

@@ -195,7 +197,9 @@ def test_create_default_noisy_quantum_virtual_machine():
195197
with pytest.raises(ValueError, match='Qubit not on device'):
196198
_ = processor.run(circuit, repetitions=100)
197199
good_qubit = cirq.GridQubit(5, 4)
198-
circuit = cirq.Circuit(cirq.H(good_qubit), cirq.measure(good_qubit))
200+
circuit = cirq.Circuit(
201+
cirq.testing.DoesNotSupportSerializationGate()(good_qubit), cirq.measure(good_qubit)
202+
)
199203
with pytest.raises(ValueError, match='.* contains a gate which is not supported.'):
200204
_ = processor.run(circuit, repetitions=100)
201205
device_specification = processor.get_device_specification()

cirq-google/cirq_google/serialization/arg_func_langs.py

+43
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import sympy
2020
from cirq_google.api import v2
2121
from cirq_google.ops import InternalGate
22+
from cirq.qis import CliffordTableau
2223

2324
SUPPORTED_FUNCTIONS_FOR_LANGUAGE: Dict[Optional[str], FrozenSet[str]] = {
2425
'': frozenset(),
@@ -455,3 +456,45 @@ def internal_gate_from_proto(
455456
num_qubits=int(msg.num_qubits),
456457
**gate_args,
457458
)
459+
460+
461+
def clifford_tableau_arg_to_proto(
462+
value: CliffordTableau, *, out: Optional[v2.program_pb2.CliffordTableau] = None
463+
):
464+
"""Writes an CliffordTableau object into an CliffordTableau proto.
465+
Args:
466+
value: The gate to encode.
467+
arg_function_language: The language to use when encoding functions. If
468+
this is set to None, it will be set to the minimal language
469+
necessary to support the features that were actually used.
470+
out: The proto to write the result into. Defaults to a new instance.
471+
Returns:
472+
The proto that was written into.
473+
"""
474+
msg = v2.program_pb2.CliffordTableau() if out is None else out
475+
msg.num_qubits = value.n
476+
msg.initial_state = value.initial_state
477+
msg.xs.extend(value.xs.flatten())
478+
msg.rs.extend(value.rs.flatten())
479+
msg.zs.extend(value.zs.flatten())
480+
return msg
481+
482+
483+
def clifford_tableau_from_proto(
484+
msg: v2.program_pb2.CliffordTableau, arg_function_language: str
485+
) -> CliffordTableau:
486+
"""Extracts a CliffordTableau object from a CliffordTableau proto.
487+
Args:
488+
msg: The proto containing a serialized value.
489+
arg_function_language: The `arg_function_language` field from
490+
`Program.Language`.
491+
Returns:
492+
The deserialized InternalGate object.
493+
"""
494+
return CliffordTableau(
495+
num_qubits=msg.num_qubits,
496+
initial_state=msg.initial_state,
497+
rs=np.array(msg.rs, dtype=bool) if msg.rs else None,
498+
xs=np.array(msg.xs, dtype=bool).reshape((2 * msg.num_qubits, -1)) if msg.xs else None,
499+
zs=np.array(msg.zs, dtype=bool).reshape((2 * msg.num_qubits, -1)) if msg.zs else None,
500+
)

cirq-google/cirq_google/serialization/arg_func_langs_test.py

+27
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,11 @@
2828
internal_gate_from_proto,
2929
ARG_LIKE,
3030
LANGUAGE_ORDER,
31+
clifford_tableau_arg_to_proto,
32+
clifford_tableau_from_proto,
3133
)
3234
from cirq_google.api import v2
35+
from cirq.qis import CliffordTableau
3336

3437

3538
@pytest.mark.parametrize(
@@ -249,3 +252,27 @@ def test_invalid_list():
249252

250253
with pytest.raises(ValueError):
251254
_ = arg_to_proto([1.0, ''])
255+
256+
257+
@pytest.mark.parametrize('lang', LANGUAGE_ORDER)
258+
def test_clifford_tableau(lang):
259+
tests = [
260+
CliffordTableau(
261+
1,
262+
0,
263+
rs=np.array([True, False], dtype=bool),
264+
xs=np.array([[True], [False]], dtype=bool),
265+
zs=np.array([[True], [False]], dtype=bool),
266+
),
267+
CliffordTableau(
268+
1,
269+
1,
270+
rs=np.array([True, True], dtype=bool),
271+
xs=np.array([[True], [False]], dtype=bool),
272+
zs=np.array([[False], [False]], dtype=bool),
273+
),
274+
]
275+
for ct in tests:
276+
proto = clifford_tableau_arg_to_proto(ct)
277+
tableau = clifford_tableau_from_proto(proto, lang)
278+
assert tableau == ct

0 commit comments

Comments
 (0)