Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

class MeasurementExecutionEngine(metaclass=ABCMeta):
@abstractmethod
def execute(
async def execute(
self, commands_collection: Sequence[TransactionCommand], *args, **kwargs
) -> str:
"""
Expand Down
23 changes: 23 additions & 0 deletions src/accml_lib/core/model/conv.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from typing import Any, Dict, Union
import jsons


def deserialse_value(value: Dict[str, Union[str, int, float, dict]], **kwargs):
def delegate_to_jsons(obj, **kwargs):
return jsons.dump(obj, **kwargs)

d = dict(int=int, float=float, dict=delegate_to_jsons)
ins = d[value["type"]]
r = ins(value["value"])
return r


def serialize_value(value, **kwargs) -> dict[str, Any]:
if isinstance(value, int):
return dict(type="int", value=value)
elif isinstance(value, float):
return dict(type="float", value=value)

d = jsons.dump(value, **kwargs)
assert isinstance(d, dict), "don't know how to serialize {value}"
return dict(type="dict", value=d)
19 changes: 19 additions & 0 deletions src/accml_lib/core/model/jsons_support.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"""register json serializer / deserialiser support functions
"""
import jsons

from .utils import command
from .output import result


def register_serializers(json_fork):

command.register_serializer_for_command(json_fork)
result.register_serializer_for_read_together(json_fork)
result.register_serializer_for_single_reading(json_fork)


def register_deserializers(json_fork):

command.register_deserializer_for_command(json_fork)
result.register_deserializer_for_single_reading(json_fork)
94 changes: 65 additions & 29 deletions src/accml_lib/core/model/output/result.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import datetime
from dataclasses import dataclass
import json
from dataclasses import dataclass, asdict
from functools import cached_property
from typing import Sequence
from typing import Sequence, Dict, Union

from ..utils.command import ReadCommand
import jsons

from ..conv import deserialse_value, serialize_value
from ..utils.command import ReadCommand, Command


@dataclass
class SingleFloat:
value : float
value: float


@dataclass
Expand All @@ -17,65 +21,97 @@ class SingleReading:

e.g. reading from one device or tune of the machine
"""

name: str
payload: object
cmd: ReadCommand

@classmethod
def from_jsons(cls, obj):
name = obj["name"]
payload = obj["payload"]
cmd = obj["cmd"]
return cls(name=name, payload=payload, cmd=cmd)
def from_jsons(cls, obj, **kwargs):
cmd = jsons.load(obj["cmd"], ReadCommand, **kwargs)
return cls(name=obj["name"], cmd=cmd, payload=deserialse_value(obj["payload"]))

def to_jsons(self, **kwargs):
import jsons

return dict(
name=self.name,
cmd=jsons.dump(self.cmd, **kwargs),
payload=serialize_value(self.payload, **kwargs),
)


@dataclass
class ReadTogether:
"""
data taken together
"""
data : Sequence[SingleReading]

data: Sequence[SingleReading]
start: datetime.datetime
end: datetime.datetime

def get(self, key):
return self._dict[key]
return self._dict[key]

@cached_property
def _dict(self):
return {d.name : d for d in self.data}
return {d.name: d for d in self.data}

def to_jsons(self, **kwargs):
import jsons

def to_jsons(self):
return dict(name=self.__class__.__name__, data=self.data)
def conv(obj):
r = jsons.dump(obj, **kwargs)
return r

return dict(data=conv(self.data), start=conv(self.start), end=conv(self.end))


@dataclass
class ResultOfExecutionStep:
#: the relevant commands reflecting state changes
#: the idea is that with data one can reconstruct
#: in which state the machine or accelerator was
cmds: Sequence[Command]
data: Sequence[ReadTogether]


@dataclass
class Result:
start: datetime.datetime
end: datetime.datetime
#: in the expected view / context of the caller
data: Sequence[ReadTogether]
data: Sequence[ResultOfExecutionStep]
#: in the expected view / context as produced by the backend
orig_data: Sequence[ReadTogether]
orig_data: Sequence[ResultOfExecutionStep]


def register_deserializer_for_single_reading(t_fork):
import jsons

def convert(obj: dict, cls: SingleReading, **kwargs):
assert cls == SingleReading, "only prepared for SingleReading here"
return cls.from_jsons(obj, **kwargs)

def single_reading_deserializer(obj: dict, cls, **kwargs):
assert cls == SingleReading, "only prepared to handle single reading"
return cls.from_jsons(obj)
jsons.set_deserializer(convert, SingleReading, high_prio=True, fork_inst=t_fork)


def dataclass_delegate_to_jsons_method(obj, **kwargs):
def register_serializer_for_single_reading(t_fork):
import jsons
r = jsons.dump(obj.to_jsons(), **kwargs)
return r

def convert(obj, cls: SingleReading, **kwargs):
if cls is not None:
assert cls == SingleReading, "only prepared to handle single reading"
return obj.to_jsons(**kwargs)

def register_deserializers_to_json_fork(t_fork):
import jsons
jsons.set_deserializer(single_reading_deserializer, SingleReading, high_prio=True, fork_inst=t_fork)
jsons.set_serializer(convert, SingleReading, high_prio=True, fork_inst=t_fork)


def register_serializers_to_json_fork(t_fork):
def register_serializer_for_read_together(t_fork):
import jsons
jsons.set_serializer(dataclass_delegate_to_jsons_method, ReadTogether, high_prio=True, fork_inst=t_fork)

def convert(obj, cls: ReadTogether, **kwargs):
if cls is not None:
assert cls == ReadTogether, "only prepared to handle read to gether"
return obj.to_jsons(**kwargs)

jsons.set_serializer(convert, ReadTogether, high_prio=True, fork_inst=t_fork)
61 changes: 58 additions & 3 deletions src/accml_lib/core/model/utils/command.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from dataclasses import dataclass
from enum import IntEnum
from typing import Sequence
from typing import Sequence, Any, Union, Dict

from accml_lib.core.model.conv import deserialse_value, serialize_value


class BehaviourOnError(IntEnum):
Expand All @@ -22,9 +24,33 @@ class Command:
#: can be the identifier of a lattice element or a device
id: str
property: str
value: object
#: the object can not be deserialized need to be more precise here
value: Union[int, float]
behaviour_on_error: BehaviourOnError

@classmethod
def from_jsons(cls, d: dict, **kwargs):
"""
Todo:
check if kwargs needs to be passed to some argument
"""
v = deserialse_value(d["value"])
return cls(
id=d["id"],
property=d["property"],
value=v,
behaviour_on_error=d["behaviour_on_error"],
)

def to_jsons(self, **kwargs):
d = dict(
id=self.id,
property=self.property,
value=serialize_value(self.value, **kwargs),
behaviour_on_error=self.behaviour_on_error,
)
return d


@dataclass
class TransactionCommand:
Expand All @@ -44,4 +70,33 @@ class CommandSequence:
commands: Sequence[TransactionCommand]


__all__ = ["BehaviourOnError", "Command", "CommandSequence", "ReadCommand", "TransactionCommand"]
def command_deserializer(obj: dict, cls: Command, **kwargs):
assert cls == Command, "only prepared to handle single reading"
r = cls.from_jsons(obj, **kwargs)
return r


def register_deserializer_for_command(t_fork):
import jsons

jsons.set_deserializer(
command_deserializer, Command, high_prio=True, fork_inst=t_fork
)


def register_serializer_for_command(t_fork):
import jsons

def conv(ins: Command, **kwargs):
return ins.to_jsons(**kwargs)

jsons.set_serializer(conv, Command, high_prio=True, fork_inst=t_fork)


__all__ = [
"BehaviourOnError",
"Command",
"CommandSequence",
"ReadCommand",
"TransactionCommand",
]
Loading
Loading