Repository: quantumlib/Cirq

Issue:
Numpy types other than float64 and complex128 are not JSON serializable
```
import numpy as np
import cirq

x = np.ones(1)[0]
print(type(x))
print(isinstance(x, float))
print(cirq.to_json(x))

x = np.ones(1)[0].astype(np.float32)
print(type(x))
print(isinstance(x, float))
print(cirq.to_json(x))
```

```
<class 'numpy.float64'>
True
1.0
<class 'numpy.float32'>
False
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-11-3be26c651848> in <module>
     10 print(type(x))
     11 print(isinstance(x, float))
---> 12 print(cirq.to_json(x))

~/Projects/Cirq/cirq/protocols/json.py in to_json(obj, file_or_fn, indent, cls)
    345     """
    346     if file_or_fn is None:
--> 347         return json.dumps(obj, indent=indent, cls=cls)
    348 
    349     if isinstance(file_or_fn, (str, pathlib.Path)):

/usr/lib/python3.7/json/__init__.py in dumps(obj, skipkeys, ensure_ascii, check_circular, allow_nan, cls, indent, separators, default, sort_keys, **kw)
    236         check_circular=check_circular, allow_nan=allow_nan, indent=indent,
    237         separators=separators, default=default, sort_keys=sort_keys,
--> 238         **kw).encode(obj)
    239 
    240 

/usr/lib/python3.7/json/encoder.py in encode(self, o)
    199         chunks = self.iterencode(o, _one_shot=True)
    200         if not isinstance(chunks, (list, tuple)):
--> 201             chunks = list(chunks)
    202         return ''.join(chunks)
    203 

/usr/lib/python3.7/json/encoder.py in _iterencode(o, _current_indent_level)
    436                     raise ValueError("Circular reference detected")
    437                 markers[markerid] = o
--> 438             o = _default(o)
    439             yield from _iterencode(o, _current_indent_level)
    440             if markers is not None:

~/Projects/Cirq/cirq/protocols/json.py in default(self, o)
    285             }
    286 
--> 287         return super().default(o)  # coverage: ignore
    288 
    289 

/usr/lib/python3.7/json/encoder.py in default(self, o)
    177 
    178         """
--> 179         raise TypeError(f'Object of type {o.__class__.__name__} '
    180                         f'is not JSON serializable')
    181 

TypeError: Object of type float32 is not JSON serializable
```


Discussion:

Resolving patch:
diff --git a/cirq/protocols/json.py b/cirq/protocols/json.py
--- a/cirq/protocols/json.py
+++ b/cirq/protocols/json.py
@@ -12,6 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 import json
+import numbers
 import pathlib
 from typing import (
     Union,
@@ -230,7 +231,13 @@ class CirqEncoder(json.JSONEncoder):
     def default(self, o):
         if hasattr(o, '_json_dict_'):
             return o._json_dict_()
-        if isinstance(o, complex):
+        if isinstance(o, np.bool_):
+            return bool(o)
+        if isinstance(o, numbers.Integral):
+            return int(o)
+        if isinstance(o, numbers.Real):
+            return float(o)
+        if isinstance(o, numbers.Complex):
             return {
                 'cirq_type': 'complex',
                 'real': o.real,


Test patch:
diff --git a/cirq/protocols/json_test.py b/cirq/protocols/json_test.py
--- a/cirq/protocols/json_test.py
+++ b/cirq/protocols/json_test.py
@@ -528,6 +528,8 @@ def _roundtrip_test_classes() -> Iterator[Tuple[str, Type]]:
 
 
 def test_builtins():
+    assert_roundtrip(True)
+    assert_roundtrip(1)
     assert_roundtrip(1 + 2j)
     assert_roundtrip({
         'test': [123, 5.5],
@@ -535,6 +537,25 @@ def test_builtins():
         '3': None,
         '0.0': [],
     })
+
+
+def test_numpy():
+    x = np.ones(1)[0]
+
+    assert_roundtrip(x.astype(np.bool))
+    assert_roundtrip(x.astype(np.int8))
+    assert_roundtrip(x.astype(np.int16))
+    assert_roundtrip(x.astype(np.int32))
+    assert_roundtrip(x.astype(np.int64))
+    assert_roundtrip(x.astype(np.uint8))
+    assert_roundtrip(x.astype(np.uint16))
+    assert_roundtrip(x.astype(np.uint32))
+    assert_roundtrip(x.astype(np.uint64))
+    assert_roundtrip(x.astype(np.float32))
+    assert_roundtrip(x.astype(np.float64))
+    assert_roundtrip(x.astype(np.complex64))
+    assert_roundtrip(x.astype(np.complex128))
+
     assert_roundtrip(np.ones((11, 5)))
     assert_roundtrip(np.arange(3))