-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
JSON Protocol #1880
Changes from 3 commits
24655a2
7d03b0a
f558974
4c1d6e0
890155e
14c910f
8dd3880
9363243
cfb7df3
f16914f
c3985b3
537925f
5ded473
6053846
01dfd8a
bd7713f
ae84e61
2e57f60
6e5f817
33d446a
5af0fde
7230890
aaaa514
fbddd6c
7450e01
46ea3a1
dc1d5e3
e40bed2
0cf6e64
9fb07fe
34a4869
c24b5fb
e78db5a
86894f3
160bd99
9180b0e
3e55ac7
8a05060
87e511f
abb0cba
b64eb9e
b2e8daa
ce9e684
d804b58
40a8c13
9f36322
23c79f6
f8df124
9cce33d
66d05de
fa94654
155d063
b51de61
6e83989
2ba7fbf
67ad592
b98e78a
bbbaa95
1034435
264faf9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
# Copyright 2019 The Cirq Developers | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# https://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
import string | ||
import json | ||
from typing import TYPE_CHECKING, Union, Any, Tuple, TypeVar, Optional, Dict, \ | ||
Iterable | ||
|
||
import numpy as np | ||
|
||
from typing_extensions import Protocol | ||
|
||
from cirq.type_workarounds import NotImplementedType | ||
|
||
TDefault = TypeVar('TDefault') | ||
|
||
RaiseTypeErrorIfNotProvided = ([],) # type: Any | ||
|
||
|
||
class SupportsJSON(Protocol): | ||
"""An object that can be turned into JSON dictionaries. | ||
|
||
Returning `NotImplemented` or `None` means "don't know how to turn into | ||
QASM". In that case fallbacks based on decomposition and known unitaries | ||
will be used instead. | ||
mpharrigan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
""" | ||
|
||
def _json_dict_(self) -> Union[None, NotImplementedType, Dict[Any, Any]]: | ||
pass | ||
|
||
|
||
def to_json_dict(obj, attribute_names): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm a bit worried that we're straying into territory that should be solved at the python level instead of at a library level. I don't have a better suggestion, there's just an alarm going off in my head about it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Synced offline with @Strilanc. His objection was to the concept of serialization and that it should be done at the python level. Python's built-in serialization is pickle which is too brittle for our case; python's |
||
d = {'cirq_type': obj.__class__.__name__} | ||
for attr_name in attribute_names: | ||
dabacon marked this conversation as resolved.
Show resolved
Hide resolved
|
||
d[attr_name] = getattr(obj, attr_name) | ||
return d | ||
|
||
|
||
class CirqEncoder(json.JSONEncoder): | ||
def default(self, o): | ||
if hasattr(o, '_json_dict_'): | ||
return o._json_dict_() | ||
if isinstance(o, np.ndarray): | ||
return o.tolist() | ||
if isinstance(o, np.int_): | ||
return o.item() | ||
return super().default(o) | ||
|
||
|
||
def cirq_object_hook(d): | ||
if 'cirq_type' in d: | ||
Strilanc marked this conversation as resolved.
Show resolved
Hide resolved
|
||
import cirq | ||
cls = getattr(cirq, d['cirq_type']) | ||
|
||
if hasattr(cls, '_from_json_dict_'): | ||
return cls._from_json_dict_(**d) | ||
|
||
del d['cirq_type'] | ||
return cls(**d) | ||
|
||
return d | ||
|
||
|
||
def to_json(obj: Any, file, *, indent=2, cls=CirqEncoder): | ||
Strilanc marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if isinstance(file, str): | ||
with open(file, 'w') as actually_a_file: | ||
return json.dump(obj, actually_a_file, indent=indent, cls=cls) | ||
|
||
return json.dump(obj, file, indent=indent, cls=cls) | ||
|
||
|
||
def read_json(file_or_fn, object_hook=cirq_object_hook): | ||
if isinstance(file_or_fn, str): | ||
with open(file_or_fn, 'r') as file: | ||
return json.load(file, object_hook=object_hook) | ||
|
||
return json.load(file_or_fn, object_hook=object_hook) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
# Copyright 2019 The Cirq Developers | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# https://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
import pytest | ||
|
||
import cirq | ||
import cirq.protocols | ||
import io | ||
|
||
|
||
def assert_roundtrip(obj, text_should_be=None): | ||
buffer = io.StringIO() | ||
cirq.protocols.to_json(obj, buffer) | ||
|
||
if text_should_be is not None: | ||
buffer.seek(0) | ||
text = buffer.read() | ||
|
||
print() | ||
print(text) | ||
|
||
assert text == text_should_be | ||
|
||
buffer.seek(0) | ||
obj2 = cirq.protocols.read_json(buffer) | ||
assert obj == obj2 | ||
|
||
|
||
def test_line_qubit_roundtrip(): | ||
q1 = cirq.LineQubit(12) | ||
|
||
buffer = io.StringIO() | ||
cirq.protocols.to_json(q1, buffer) | ||
|
||
buffer.seek(0) | ||
text = buffer.read() | ||
|
||
print() | ||
print(text) | ||
|
||
assert text == """{ | ||
"cirq_type": "LineQubit", | ||
"x": 12 | ||
}""" | ||
|
||
buffer.seek(0) | ||
q2 = cirq.protocols.read_json(buffer) | ||
assert q1 == q2 | ||
|
||
|
||
def test_op_roundtrip(): | ||
q = cirq.LineQubit(5) | ||
op1 = cirq.Rx(.123).on(q) | ||
|
||
buffer = io.StringIO() | ||
cirq.protocols.to_json(op1, buffer) | ||
|
||
buffer.seek(0) | ||
text = buffer.read() | ||
assert text == """{ | ||
"cirq_type": "GateOperation", | ||
"gate": { | ||
"cirq_type": "XPowGate", | ||
"exponent": 0.03915211600060625, | ||
"global_shift": -0.5 | ||
}, | ||
"qubits": [ | ||
{ | ||
"cirq_type": "LineQubit", | ||
"x": 5 | ||
} | ||
] | ||
}""" | ||
|
||
print() | ||
print(text) | ||
|
||
buffer.seek(0) | ||
op2 = cirq.protocols.read_json(buffer) | ||
assert op1 == op2 | ||
|
||
|
||
def test_gridqubit_roundtrip(): | ||
q = cirq.GridQubit(15, 18) | ||
assert_roundtrip(q, text_should_be="""{ | ||
"cirq_type": "GridQubit", | ||
"row": 15, | ||
"col": 18 | ||
}""") |
Uh oh!
There was an error while loading. Please reload this page.