Skip to content

Commit

Permalink
Merge pull request #136 from Blueqat/json-format
Browse files Browse the repository at this point in the history
Json serializer/deserializer
  • Loading branch information
gyu-don authored Jul 29, 2021
2 parents b334973 + 031c443 commit 429f5c9
Show file tree
Hide file tree
Showing 4 changed files with 207 additions and 0 deletions.
2 changes: 2 additions & 0 deletions blueqat/circuit_funcs/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
"""This module is EXPERIMENTAL FEATURES. Provided functions may be removed or destructive changed.
This module provides functions that handles Circuits."""
15 changes: 15 additions & 0 deletions blueqat/circuit_funcs/flatten.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from .. import Circuit
from .. import gate as g

def flatten(c: Circuit) -> Circuit:
"""expands slice and multiple targets into single target"""
n_qubits = c.n_qubits
ops = []
for op in c.ops:
if isinstance(op, (g.OneQubitGate, g.Measurement, g.Reset)):
ops += [op.create(t, op.params) for t in op.target_iter(n_qubits)]
elif isinstance(op, g.TwoQubitGate):
ops += [op.create(t, op.params) for t in op.control_target_iter(n_qubits)]
else:
raise ValueError(f"Cannot process operation {op.lowername}.")
return Circuit(n_qubits, ops)
83 changes: 83 additions & 0 deletions blueqat/circuit_funcs/json_serializer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
"""Defines JSON serializer and deserializer."""
import typing
from blueqat import Circuit

from ..gateset import create
from .flatten import flatten

SCHEMA_NAME = 'blueqat-circuit'
SCHEMA_VERSION = "1"

if typing.TYPE_CHECKING:
from blueqat.gate import Operation
try:
from typing import Any, Dict, List, TypedDict
except ImportError:
CircuitJsonDict = Dict[str, Any]
OpJsonDict = Dict[str, Any]
else:
class SchemaJsonDict(TypedDict):
"""Schema header for detect data type"""
name: str
version: str

class OpJsonDict(TypedDict):
"""Data type of Operation"""
name: str
params: List[float]
targets: List[int]

class CircuitJsonDict(TypedDict):
"""Data type of Circuit"""
schema: SchemaJsonDict
n_qubits: int
ops: List[OpJsonDict]


def serialize(c: Circuit) -> 'CircuitJsonDict':
"""Serialize Circuit into JSON type dict.
In this implementation, serialized circuit is flattened.
However, it's not specifications of JSON schema.
"""
def serialize_op(op: 'Operation') -> 'OpJsonDict':
targets = op.targets
if isinstance(targets, slice):
raise TypeError('Not flatten circuit.')
if isinstance(targets, int):
targets = [targets]
if isinstance(targets, tuple):
targets = list(targets)
return {
'name': str(op.lowername),
'params': [float(p) for p in op.params],
'targets': targets
}

c = flatten(c)
return {
'schema': {
'name': SCHEMA_NAME,
'version': SCHEMA_VERSION
},
'n_qubits': c.n_qubits,
'ops': [serialize_op(op) for op in c.ops]
}


def deserialize(data: 'CircuitJsonDict') -> Circuit:
"""Deserialize JSON type dict into Circuit"""
def make_op(opdata: 'OpJsonDict') -> 'Operation':
return create(opdata['name'],
tuple(opdata['targets']),
tuple(float(p) for p in opdata['params']))
schema = data.get('schema', {})
if schema.get('name', '') != SCHEMA_NAME:
raise ValueError('Invalid schema')
if schema.get('version', '') != SCHEMA_VERSION:
raise ValueError('Unknown schema version')
n_qubits = data['n_qubits']
ops = data['ops']
return Circuit(n_qubits, [
make_op(opdata) for opdata in ops
])
107 changes: 107 additions & 0 deletions tests/test_json.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import json
import numpy as np
from blueqat import Circuit
from blueqat.circuit_funcs.json_serializer import serialize, deserialize
from blueqat.circuit_funcs.flatten import flatten


def test_json_dump_load():
"""A Circuit and deserialize(serialize())ed circuit returns same result.
(However, it doesn't means they're same Circuit.)"""
c = Circuit().h[:3].x[4].u(1.2, 3.4, 2.3, 1.0)[0].h[:].u(1.2, 3.4, 2.3)[1]
d = serialize(c)
j = json.dumps(d)
d2 = json.loads(j)
c2 = deserialize(d2)
np.allclose(c.run(), c2.run())


def test_serialize_idempotent():
"""Serialized circuit and serialize(deserialize(serialize()))ed circuit are same."""
c0 = Circuit().h[:3].x[4].cx[1, 3].u(1.2, 3.4, 2.3, 1.0)[0]
c0.h[:].u(1.2, 3.4, 2.3)[1:].m[:]
d1 = serialize(c0)
c1 = deserialize(d1)
d2 = serialize(c1)
c2 = deserialize(d2)
assert d1 == d2
assert repr(c1) == repr(c2)


def test_serialize():
"""Testing serialized result. This JSON may changed in the future."""
c = Circuit().r(0.2)[0, 2].h[:].m[1]
d = serialize(c)
assert d == {
'schema': {
'name': 'blueqat-circuit',
'version': '1'
},
'n_qubits': 3,
'ops': [
{
'name': 'phase',
'targets': [0],
'params': [0.2]
},
{
'name': 'phase',
'targets': [2],
'params': [0.2]
},
{
'name': 'h',
'targets': [0],
'params': []
},
{
'name': 'h',
'targets': [1],
'params': []
},
{
'name': 'h',
'targets': [2],
'params': []
},
{
'name': 'measure',
'targets': [1],
'params': []
},
]
}


def test_deserialize():
"""Testing deserialize result. This JSON may changed in the future."""
s = """{
"schema": {"name": "blueqat-circuit", "version": "1"},
"n_qubits": 3,
"ops": [
{"name": "phase", "targets": [0], "params": [0.2]},
{"name": "phase", "targets": [2], "params": [0.2]},
{"name": "h", "targets": [0], "params": []},
{"name": "h", "targets": [1], "params": []},
{"name": "h", "targets": [2], "params": []},
{"name": "measure", "targets": [1], "params": []}
]}"""
d = json.loads(s)
c1 = deserialize(d)
c2 = flatten(Circuit().r(0.2)[0, 2].h[:].m[1])


def test_deserialize_unflatten():
"""Testing deserialize unflatten JSON file."""
s = """{
"schema": {"name": "blueqat-circuit", "version": "1"},
"n_qubits": 3,
"ops": [
{"name": "phase", "targets": [0, 2], "params": [0.2]},
{"name": "h", "targets": [0, 1, 2], "params": []},
{"name": "measure", "targets": [1], "params": []}
]}"""
d = json.loads(s)
c1 = deserialize(d)
c2 = Circuit().r(0.2)[0, 2].h[0, 1, 2].m[1]
assert repr(c1) == repr(c2)

0 comments on commit 429f5c9

Please sign in to comment.