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

Add serialization support to more gates #6479

Merged
merged 4 commits into from
Mar 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion cirq-core/cirq/testing/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,12 @@

from cirq.testing.equivalent_repr_eval import assert_equivalent_repr

from cirq.testing.gate_features import SingleQubitGate, TwoQubitGate, ThreeQubitGate
from cirq.testing.gate_features import (
SingleQubitGate,
TwoQubitGate,
ThreeQubitGate,
DoesNotSupportSerializationGate,
)

from cirq.testing.json import assert_json_roundtrip_works

Expand Down
10 changes: 10 additions & 0 deletions cirq-core/cirq/testing/gate_features.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,13 @@ class ThreeQubitGate(raw_types.Gate):

def _num_qubits_(self) -> int:
return 3


class DoesNotSupportSerializationGate(raw_types.Gate):
"""A gate that can't be serialized."""

def __init__(self, n_qubits: int = 1):
self.n_qubits = n_qubits

def _num_qubits_(self) -> int:
return self.n_qubits
23 changes: 23 additions & 0 deletions cirq-google/cirq_google/api/v2/program.proto
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,9 @@ message Operation {
WaitGate waitgate = 16;
InternalGate internalgate = 17;
CouplerPulseGate couplerpulsegate = 18;
IdentityGate identitygate = 19;
HPowGate hpowgate = 20;
SingleQubitCliffordGate singlequbitcliffordgate = 21;
}

// Map from the argument name to the Argument needed to fully specify
Expand Down Expand Up @@ -434,4 +437,24 @@ message CouplerPulseGate{
optional FloatArg coupling_mhz = 4;
optional FloatArg q0_detune_mhz = 5;
optional FloatArg q1_detune_mhz = 6;
}

message CliffordTableau {
optional int32 num_qubits = 1; // Number of qubits the CliffordTableau acts on.
optional int32 initial_state = 2; // The initial state.
repeated bool rs = 3; // A flattened version of the `rs` array.
repeated bool xs = 4; // A flattened version of the `xs` array.
repeated bool zs = 5; // A flattened version of the `zs` array.
}

message SingleQubitCliffordGate {
CliffordTableau tableau = 1;
}

message IdentityGate {
repeated uint32 qid_shape = 1;
}

message HPowGate {
FloatArg exponent = 1;
}
104 changes: 56 additions & 48 deletions cirq-google/cirq_google/api/v2/program_pb2.py

Large diffs are not rendered by default.

108 changes: 105 additions & 3 deletions cirq-google/cirq_google/api/v2/program_pb2.pyi

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion cirq-google/cirq_google/devices/grid_device_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,9 @@ def test_grid_device_validate_operations_negative():
device.validate_operation(cirq.CZ(q00, q10))

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


@pytest.mark.parametrize(
Expand Down
4 changes: 3 additions & 1 deletion cirq-google/cirq_google/engine/engine_processor_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,9 @@ def test_get_device():
with pytest.raises(ValueError):
device.validate_operation(cirq.X(cirq.GridQubit(1, 2)))
with pytest.raises(ValueError):
device.validate_operation(cirq.H(cirq.GridQubit(0, 0)))
device.validate_operation(
cirq.testing.DoesNotSupportSerializationGate()(cirq.GridQubit(0, 0))
)
with pytest.raises(ValueError):
device.validate_operation(cirq.CZ(cirq.GridQubit(1, 1), cirq.GridQubit(2, 2)))

Expand Down
4 changes: 3 additions & 1 deletion cirq-google/cirq_google/engine/engine_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -824,6 +824,8 @@ def test_get_engine_device(get_processor):
with pytest.raises(ValueError):
device.validate_operation(cirq.X(cirq.GridQubit(1, 2)))
with pytest.raises(ValueError):
device.validate_operation(cirq.H(cirq.GridQubit(0, 0)))
device.validate_operation(
cirq.testing.DoesNotSupportSerializationGate()(cirq.GridQubit(0, 0))
)
with pytest.raises(ValueError):
device.validate_operation(cirq.CZ(cirq.GridQubit(1, 1), cirq.GridQubit(2, 2)))
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ def _test_processor(processor: cg.engine.abstract_processor.AbstractProcessor):
circuit = cirq.Circuit(cirq.X(bad_qubit), cirq.measure(bad_qubit))
with pytest.raises(ValueError, match='Qubit not on device'):
_ = processor.run(circuit, repetitions=100)
circuit = cirq.Circuit(cirq.H(good_qubit), cirq.measure(good_qubit))
circuit = cirq.Circuit(
cirq.testing.DoesNotSupportSerializationGate()(good_qubit), cirq.measure(good_qubit)
)
with pytest.raises(ValueError, match='Cannot serialize op'):
_ = processor.run(circuit, repetitions=100)

Expand Down Expand Up @@ -195,7 +197,9 @@ def test_create_default_noisy_quantum_virtual_machine():
with pytest.raises(ValueError, match='Qubit not on device'):
_ = processor.run(circuit, repetitions=100)
good_qubit = cirq.GridQubit(5, 4)
circuit = cirq.Circuit(cirq.H(good_qubit), cirq.measure(good_qubit))
circuit = cirq.Circuit(
cirq.testing.DoesNotSupportSerializationGate()(good_qubit), cirq.measure(good_qubit)
)
with pytest.raises(ValueError, match='.* contains a gate which is not supported.'):
_ = processor.run(circuit, repetitions=100)
device_specification = processor.get_device_specification()
Expand Down
43 changes: 43 additions & 0 deletions cirq-google/cirq_google/serialization/arg_func_langs.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import sympy
from cirq_google.api import v2
from cirq_google.ops import InternalGate
from cirq.qis import CliffordTableau

SUPPORTED_FUNCTIONS_FOR_LANGUAGE: Dict[Optional[str], FrozenSet[str]] = {
'': frozenset(),
Expand Down Expand Up @@ -455,3 +456,45 @@ def internal_gate_from_proto(
num_qubits=int(msg.num_qubits),
**gate_args,
)


def clifford_tableau_arg_to_proto(
value: CliffordTableau, *, out: Optional[v2.program_pb2.CliffordTableau] = None
):
"""Writes an CliffordTableau object into an CliffordTableau proto.
Args:
value: The gate to encode.
arg_function_language: The language to use when encoding functions. If
this is set to None, it will be set to the minimal language
necessary to support the features that were actually used.
out: The proto to write the result into. Defaults to a new instance.
Returns:
The proto that was written into.
"""
msg = v2.program_pb2.CliffordTableau() if out is None else out
msg.num_qubits = value.n
msg.initial_state = value.initial_state
msg.xs.extend(value.xs.flatten())
msg.rs.extend(value.rs.flatten())
msg.zs.extend(value.zs.flatten())
return msg


def clifford_tableau_from_proto(
msg: v2.program_pb2.CliffordTableau, arg_function_language: str
) -> CliffordTableau:
"""Extracts a CliffordTableau object from a CliffordTableau proto.
Args:
msg: The proto containing a serialized value.
arg_function_language: The `arg_function_language` field from
`Program.Language`.
Returns:
The deserialized InternalGate object.
"""
return CliffordTableau(
num_qubits=msg.num_qubits,
initial_state=msg.initial_state,
rs=np.array(msg.rs, dtype=bool) if msg.rs else None,
xs=np.array(msg.xs, dtype=bool).reshape((2 * msg.num_qubits, -1)) if msg.xs else None,
zs=np.array(msg.zs, dtype=bool).reshape((2 * msg.num_qubits, -1)) if msg.zs else None,
)
27 changes: 27 additions & 0 deletions cirq-google/cirq_google/serialization/arg_func_langs_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,11 @@
internal_gate_from_proto,
ARG_LIKE,
LANGUAGE_ORDER,
clifford_tableau_arg_to_proto,
clifford_tableau_from_proto,
)
from cirq_google.api import v2
from cirq.qis import CliffordTableau


@pytest.mark.parametrize(
Expand Down Expand Up @@ -249,3 +252,27 @@ def test_invalid_list():

with pytest.raises(ValueError):
_ = arg_to_proto([1.0, ''])


@pytest.mark.parametrize('lang', LANGUAGE_ORDER)
def test_clifford_tableau(lang):
tests = [
CliffordTableau(
1,
0,
rs=np.array([True, False], dtype=bool),
xs=np.array([[True], [False]], dtype=bool),
zs=np.array([[True], [False]], dtype=bool),
),
CliffordTableau(
1,
1,
rs=np.array([True, True], dtype=bool),
xs=np.array([[True], [False]], dtype=bool),
zs=np.array([[False], [False]], dtype=bool),
),
]
for ct in tests:
proto = clifford_tableau_arg_to_proto(ct)
tableau = clifford_tableau_from_proto(proto, lang)
assert tableau == ct
Loading
Loading