Skip to content

Support serialization of SingleQubitCliffordGate #6418

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

Closed
wants to merge 1 commit into from
Closed
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
13 changes: 13 additions & 0 deletions cirq-google/cirq_google/api/v2/program.proto
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ message Operation {
MeasurementGate measurementgate = 15;
WaitGate waitgate = 16;
InternalGate internalgate = 17;
SingleQubitCliffordGate singlequbitcliffordgate = 18;
}

// Map from the argument name to the Argument needed to fully specify
Expand Down Expand Up @@ -424,4 +425,16 @@ message InternalGate{
string module = 2; // Gate module.
int32 num_qubits = 3; // Number of qubits. Required during deserialization.
map<string, Arg> gate_args = 4; // Gate args.
}

message CliffordTableau {
optional int32 num_qubits = 1;
optional int32 initial_state = 2;
optional bytes rs = 3;
optional bytes xs = 4;
optional bytes zs = 5;
}

message SingleQubitCliffordGate {
CliffordTableau tableau = 1;
}
96 changes: 50 additions & 46 deletions cirq-google/cirq_google/api/v2/program_pb2.py

Large diffs are not rendered by default.

65 changes: 62 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.

47 changes: 47 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,49 @@ 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 = value.xs.tobytes()
msg.rs = value.rs.tobytes()
msg.zs = value.zs.tobytes()
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.frombuffer(msg.rs, dtype=bool) if msg.rs else None,
xs=np.frombuffer(msg.xs, dtype=bool).reshape((2 * msg.num_qubits, -1)) if msg.xs else None,
zs=np.frombuffer(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 @@ -26,10 +26,13 @@
float_arg_to_proto,
internal_gate_arg_to_proto,
internal_gate_from_proto,
clifford_tableau_arg_to_proto,
clifford_tableau_from_proto,
ARG_LIKE,
LANGUAGE_ORDER,
)
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
12 changes: 11 additions & 1 deletion cirq-google/cirq_google/serialization/circuit_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,11 @@ def _serialize_gate_op(
"""
gate = op.gate

if isinstance(gate, InternalGate):
if isinstance(gate, cirq.ops.SingleQubitCliffordGate):
arg_func_langs.clifford_tableau_arg_to_proto(
gate._clifford_tableau, out=msg.singlequbitcliffordgate.tableau
)
elif isinstance(gate, InternalGate):
arg_func_langs.internal_gate_arg_to_proto(gate, out=msg.internalgate)
elif isinstance(gate, cirq.XPowGate):
arg_func_langs.float_arg_to_proto(
Expand Down Expand Up @@ -574,6 +578,12 @@ def _deserialize_gate_op(
op = arg_func_langs.internal_gate_from_proto(
operation_proto.internalgate, arg_function_language=arg_function_language
)(*qubits)
elif which_gate_type == 'singlequbitcliffordgate':
tableau = arg_func_langs.clifford_tableau_from_proto(
operation_proto.singlequbitcliffordgate.tableau,
arg_function_language=arg_function_language,
)
op = cirq.ops.SingleQubitCliffordGate.from_clifford_tableau(tableau)(*qubits)
else:
raise ValueError(
f'Unsupported serialized gate with type "{which_gate_type}".'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,23 @@ def circuit_proto(json: Dict, qubits: List[str]):
}
),
),
(
cirq.ops.SingleQubitCliffordGate.X(Q0),
op_proto(
{
'singlequbitcliffordgate': {
'tableau': {
'num_qubits': 1,
'initial_state': 0,
'rs': 'AAE=',
'xs': 'AQA=',
'zs': 'AAE=',
}
},
'qubit_constant_index': [0],
}
),
),
]


Expand Down Expand Up @@ -668,3 +685,12 @@ def test_measurement_gate_deserialize() -> None:
msg = cg.CIRCUIT_SERIALIZER.serialize(circuit)

assert cg.CIRCUIT_SERIALIZER.deserialize(msg) == circuit


def test_circuit_with_cliffords():
q = cirq.NamedQubit('q')
circuit = cirq.Circuit(
g(q) for g in cirq.ops.SingleQubitCliffordGate.all_single_qubit_cliffords
)
msg = cg.CIRCUIT_SERIALIZER.serialize(circuit)
assert cg.CIRCUIT_SERIALIZER.deserialize(msg) == circuit