Skip to content

JSON Protocol #1880

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

Merged
merged 60 commits into from
Aug 24, 2019
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
24655a2
JSON Protocol
mpharrigan Jul 25, 2019
7d03b0a
Allow extensibility
mpharrigan Jul 26, 2019
f558974
Add to GridQubit
mpharrigan Jul 26, 2019
4c1d6e0
Explicit resolvers and improved docstrings
mpharrigan Jul 29, 2019
890155e
[json] percolate functions to top level
mpharrigan Jul 31, 2019
14c910f
Merge remote-tracking branch 'origin/master' into json-protocol
mpharrigan Aug 16, 2019
8dd3880
Automated testing
mpharrigan Aug 16, 2019
9363243
JSON support for Gate
mpharrigan Aug 16, 2019
cfb7df3
More JSON goodness
mpharrigan Aug 16, 2019
f16914f
rename to TEST_OBJECTS
mpharrigan Aug 16, 2019
c3985b3
Automatic testing of every class importable from cirq
mpharrigan Aug 19, 2019
537925f
Test singletons too
mpharrigan Aug 19, 2019
5ded473
Everything to support cirq.Circuit
mpharrigan Aug 19, 2019
6053846
Distinguish between things we dont want to serialize
mpharrigan Aug 19, 2019
01dfd8a
clean up
mpharrigan Aug 19, 2019
bd7713f
Merge remote-tracking branch 'origin/master' into json-protocol
mpharrigan Aug 19, 2019
ae84e61
CSWAP fix has been merged in
mpharrigan Aug 19, 2019
2e57f60
Implement serialization for NamedQubit
mpharrigan Aug 19, 2019
6e5f817
Implement serialization for PhasedXPowGate
mpharrigan Aug 19, 2019
33d446a
remove outdated note
mpharrigan Aug 19, 2019
5af0fde
give this assertion its own test
mpharrigan Aug 19, 2019
7230890
Format
mpharrigan Aug 20, 2019
aaaa514
Pylint
mpharrigan Aug 20, 2019
fbddd6c
Types
mpharrigan Aug 20, 2019
7450e01
Merge remote-tracking branch 'origin/master' into json-protocol
mpharrigan Aug 20, 2019
46ea3a1
There's been a new type
mpharrigan Aug 20, 2019
dc1d5e3
Imports for mypy
mpharrigan Aug 20, 2019
e40bed2
mypy hoops
mpharrigan Aug 20, 2019
0cf6e64
extreme hoops to get both formatter and mypy happy
mpharrigan Aug 20, 2019
9fb07fe
Full coverage
mpharrigan Aug 20, 2019
34a4869
Format
mpharrigan Aug 20, 2019
c24b5fb
Pylint
mpharrigan Aug 20, 2019
e78db5a
Mypy
mpharrigan Aug 20, 2019
86894f3
Test coverage for default ser/deser code paths
mpharrigan Aug 20, 2019
160bd99
coverage
mpharrigan Aug 20, 2019
9180b0e
Put extra imports behind `if TYPE_CHECKING`
mpharrigan Aug 22, 2019
3e55ac7
Merge remote-tracking branch 'origin/master' into json-protocol
mpharrigan Aug 22, 2019
8a05060
Keep up with new public classes being added
mpharrigan Aug 22, 2019
87e511f
Tack on support for sympy.Symbol
mpharrigan Aug 22, 2019
abb0cba
Namespace 3rd party objects
mpharrigan Aug 22, 2019
b64eb9e
self._num_qubits -> self.num_qubits()
mpharrigan Aug 22, 2019
b2e8daa
remove superflous comment
mpharrigan Aug 22, 2019
ce9e684
Document CirqEncoder
mpharrigan Aug 22, 2019
d804b58
Document DEFAULT_RESOLVERS
mpharrigan Aug 22, 2019
40a8c13
Format
mpharrigan Aug 22, 2019
9f36322
Merge remote-tracking branch 'origin/master' into json-protocol
mpharrigan Aug 22, 2019
23c79f6
Messed up the merge a bit
mpharrigan Aug 22, 2019
f8df124
More changes due to breaking change
mpharrigan Aug 22, 2019
9cce33d
Missed this one
mpharrigan Aug 22, 2019
66d05de
deser -> deserialization
mpharrigan Aug 23, 2019
fa94654
read_json -> cirq.read_json
mpharrigan Aug 23, 2019
155d063
invert control
mpharrigan Aug 23, 2019
b51de61
Help developers with an error message
mpharrigan Aug 23, 2019
6e83989
format
mpharrigan Aug 23, 2019
2ba7fbf
Merge remote-tracking branch 'origin/master' into json-protocol
mpharrigan Aug 23, 2019
67ad592
Document to_json
mpharrigan Aug 23, 2019
b98e78a
head explosion emoji
mpharrigan Aug 23, 2019
bbbaa95
manual format
mpharrigan Aug 23, 2019
1034435
skip coverage
mpharrigan Aug 23, 2019
264faf9
Merge branch 'master' into json-protocol
dabacon Aug 24, 2019
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
3 changes: 3 additions & 0 deletions cirq/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@
qasm,
QasmArgs,
qid_shape,
read_json,
resolve_parameters,
SupportsApplyChannel,
SupportsConsistentApplyUnitary,
Expand All @@ -347,6 +348,8 @@
SupportsQasmWithArgsAndQubits,
SupportsTraceDistanceBound,
SupportsUnitary,
to_json,
to_json_dict,
trace_distance_bound,
unitary,
validate_mixture,
Expand Down
5 changes: 4 additions & 1 deletion cirq/devices/grid_qubit.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

from typing import Dict, List, Tuple

from cirq import ops
from cirq import ops, protocols


class GridQubit(ops.Qid):
Expand Down Expand Up @@ -139,6 +139,9 @@ def __repr__(self):
def __str__(self):
return '({}, {})'.format(self.row, self.col)

def _json_dict_(self):
return protocols.to_json_dict(self, ['row', 'col'])

def __add__(self, other: Tuple[int, int]) -> 'GridQubit':
if not (isinstance(other, tuple) and len(other) == 2 and
all(isinstance(x, int) for x in other)):
Expand Down
10 changes: 10 additions & 0 deletions cirq/devices/grid_qubit_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,3 +167,13 @@ def test_from_proto_bad_dict():
cirq.GridQubit.from_proto_dict({})
with pytest.raises(ValueError):
cirq.GridQubit.from_proto_dict({'nothing': 1})


def test_to_json():
q = cirq.GridQubit(5, 6)
d = q._json_dict_()
assert d == {
'cirq_type': 'GridQubit',
'row': 5,
'col': 6,
}
5 changes: 4 additions & 1 deletion cirq/line/line_qubit.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import functools
from typing import List

from cirq import ops
from cirq import ops, protocols

@functools.total_ordering
class LineQubit(ops.Qid):
Expand Down Expand Up @@ -84,3 +84,6 @@ def __rsub__(self, other: int) -> 'LineQubit':

def __neg__(self) -> 'LineQubit':
return LineQubit(-self.x)

def _json_dict_(self):
return protocols.to_json_dict(self, ['x'])
7 changes: 7 additions & 0 deletions cirq/line/line_qubit_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,10 @@ def test_addition_subtraction_type_error():

def test_neg():
assert -cirq.LineQubit(1) == cirq.LineQubit(-1)


def test_json_dict():
assert cirq.LineQubit(5)._json_dict_() == {
'cirq_type': 'LineQubit',
'x': 5,
}
15 changes: 15 additions & 0 deletions cirq/ops/common_gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,17 @@ def __repr__(self):
def _value_equality_values_(self):
return self.num_qubits(), self.key, self.invert_mask

def _json_dict_(self):
return {'cirq_type': self.__class__.__name__,
'num_qubits': self.num_qubits(),
'key': self.key,
'invert_mask': self.invert_mask}

@classmethod
def _from_json_dict_(cls, num_qubits, key, invert_mask, **kwargs):
return cls(num_qubits=num_qubits, key=key,
invert_mask=tuple(invert_mask))


def _default_measurement_key(qubits: Iterable[raw_types.Qid]) -> str:
return ','.join(str(q) for q in qubits)
Expand Down Expand Up @@ -665,6 +676,10 @@ def _qasm_(self, args: protocols.QasmArgs,
def _value_equality_values_(self):
return self.num_qubits(),

def _json_dict_(self):
return {'cirq_type': self.__class__.__name__,
'num_qubits': self._num_qubits}


class HPowGate(eigen_gate.EigenGate, gate_features.SingleQubitGate):
"""A Gate that performs a rotation around the X+Z axis of the Bloch sphere.
Expand Down
7 changes: 7 additions & 0 deletions cirq/ops/eigen_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ def __init__(self, *, # Forces keyword args.
def exponent(self) -> Union[sympy.Basic, float]:
return self._exponent

@property
def global_shift(self) -> float:
return self._global_shift

# virtual method
def _with_exponent(self: TSelf,
exponent: Union[sympy.Basic, float]) -> TSelf:
Expand Down Expand Up @@ -318,6 +322,9 @@ def _resolve_parameters_(self: TSelf, param_resolver) -> TSelf:
return self._with_exponent(
exponent=param_resolver.value_of(self._exponent))

def _json_dict_(self):
return protocols.to_json_dict(self, ['exponent', 'global_shift'])


def _lcm(vals: Iterable[int]) -> int:
t = 1
Expand Down
3 changes: 3 additions & 0 deletions cirq/ops/fsim_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,9 @@ def __repr__(self):
return 'cirq.FSimGate(theta={}, phi={})'.format(proper_repr(self.theta),
proper_repr(self.phi))

def _json_dict_(self):
return protocols.to_json_dict(self, ['theta', 'phi'])


def _format_rads(args: 'cirq.CircuitDiagramInfoArgs', radians: float) -> str:
if cirq.is_parameterized(radians):
Expand Down
8 changes: 8 additions & 0 deletions cirq/ops/fsim_gate_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,3 +234,11 @@ def test_fsim_iswap_cphase(theta, phi):
iswap_cphase = cirq.Circuit.from_ops((iswap.on(q0, q1), cphase.on(q0, q1)))
fsim = cirq.FSimGate(theta=theta, phi=phi)
assert np.allclose(cirq.unitary(iswap_cphase), cirq.unitary(fsim))


def test_fsim_json_dict():
assert cirq.FSimGate(theta=0.123, phi=0.456)._json_dict_() == {
'cirq_type': 'FSimGate',
'theta': 0.123,
'phi': 0.456,
}
3 changes: 3 additions & 0 deletions cirq/ops/gate_operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ def __str__(self):
return '{}({})'.format(self.gate,
', '.join(str(e) for e in self.qubits))

def _json_dict_(self):
return protocols.to_json_dict(self, ['gate', 'qubits'])

def _group_interchangeable_qubits(self) -> Tuple[
Union[raw_types.Qid,
Tuple[int, FrozenSet[raw_types.Qid]]],
Expand Down
5 changes: 4 additions & 1 deletion cirq/ops/global_phase_op.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

import numpy as np

from cirq import value
from cirq import value, protocols
from cirq.ops import raw_types


Expand Down Expand Up @@ -62,3 +62,6 @@ def __str__(self):

def __repr__(self):
return 'cirq.GlobalPhaseOperation({!r})'.format(self.coefficient)

def _json_dict_(self):
return protocols.to_json_dict(self, ['coefficient'])
7 changes: 7 additions & 0 deletions cirq/ops/global_phase_op_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,3 +182,10 @@ def test_diagram():
]), """
global phase: -0.5π
""")


def test_global_phase_op_json_dict():
assert cirq.GlobalPhaseOperation(-1j)._json_dict_() == {
'cirq_type': 'GlobalPhaseOperation',
'coefficient': -1j,
}
20 changes: 16 additions & 4 deletions cirq/ops/pauli_gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def phased_pauli_product(
) -> Tuple[complex, Union['Pauli', 'common_gates.IdentityGate']]:
if self == other:
return 1, common_gates.I
return 1j**other.relative_index(self), self.third(other)
return 1j ** other.relative_index(self), self.third(other)

def __gt__(self, other):
if not isinstance(other, Pauli):
Expand Down Expand Up @@ -94,6 +94,11 @@ def __pow__(self: '_PauliX',
exponent: Union[sympy.Basic, float]) -> common_gates.XPowGate:
return common_gates.XPowGate(exponent=exponent)

@classmethod
def _from_json_dict_(cls, exponent, global_shift, **kwargs):
assert global_shift == 0
return cls(exponent=exponent)


class _PauliY(Pauli, common_gates.YPowGate):
def __init__(self, *, exponent: Union[sympy.Basic, float] = 1.0):
Expand All @@ -104,6 +109,11 @@ def __pow__(self: '_PauliY',
exponent: Union[sympy.Basic, float]) -> common_gates.YPowGate:
return common_gates.YPowGate(exponent=exponent)

@classmethod
def _from_json_dict_(cls, exponent, global_shift, **kwargs):
assert global_shift == 0
return cls(exponent=exponent)


class _PauliZ(Pauli, common_gates.ZPowGate):
def __init__(self, *, exponent: Union[sympy.Basic, float] = 1.0):
Expand All @@ -114,6 +124,11 @@ def __pow__(self: '_PauliZ',
exponent: Union[sympy.Basic, float]) -> common_gates.ZPowGate:
return common_gates.ZPowGate(exponent=exponent)

@classmethod
def _from_json_dict_(cls, exponent, global_shift, **kwargs):
assert global_shift == 0
return cls(exponent=exponent)


# The Pauli X gate.
#
Expand All @@ -123,7 +138,6 @@ def __pow__(self: '_PauliZ',
# [1, 0]]
X = _PauliX()


# The Pauli Y gate.
#
# Matrix:
Expand All @@ -132,7 +146,6 @@ def __pow__(self: '_PauliZ',
# [i, 0]]
Y = _PauliY()


# The Pauli Z gate.
#
# Matrix:
Expand All @@ -141,5 +154,4 @@ def __pow__(self: '_PauliZ',
# [0, -1]]
Z = _PauliZ()


Pauli._XYZ = (X, Y, Z)
5 changes: 4 additions & 1 deletion cirq/ops/raw_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

import abc

from cirq import value
from cirq import value, protocols
from cirq.protocols import decompose, inverse, qid_shape_protocol

if TYPE_CHECKING:
Expand Down Expand Up @@ -255,6 +255,9 @@ def _qid_shape_(self) -> Tuple[int, ...]:
(3, 3) for a 2-qutrit ternary gate.
"""

def _json_dict_(self):
return protocols.to_json_dict(self, attribute_names=[])


class Operation(metaclass=abc.ABCMeta):
"""An effect applied to a collection of qubits.
Expand Down
7 changes: 7 additions & 0 deletions cirq/ops/raw_types_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,3 +275,10 @@ def _qid_shape_(self):
assert len(shape_op.qubits) == 4
assert cirq.qid_shape(shape_op) == (1, 2, 3, 4)
assert cirq.num_qubits(shape_op) == 4


def test_gate_json_dict():
g = cirq.CSWAP # not an eigen gate (which has its own _json_dict_)
assert g._json_dict_() == {
'cirq_type': 'CSwapGate',
}
3 changes: 3 additions & 0 deletions cirq/protocols/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@
from cirq.protocols.inverse import (
inverse,
)
from cirq.protocols.json import (
to_json, read_json, to_json_dict
)
from cirq.protocols.measurement_key import (
is_measurement,
measurement_key,
Expand Down
Loading