Skip to content

Commit

Permalink
Merge ea0c8e4 into 6995a0a
Browse files Browse the repository at this point in the history
  • Loading branch information
terrorfisch committed Jul 5, 2018
2 parents 6995a0a + ea0c8e4 commit bb9f405
Show file tree
Hide file tree
Showing 19 changed files with 131 additions and 71 deletions.
7 changes: 4 additions & 3 deletions qctoolkit/pulses/function_pulse_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import sympy

from qctoolkit.expressions import ExpressionScalar
from qctoolkit.serialization import Serializer
from qctoolkit.serialization import Serializer, Serializable

from qctoolkit.utils.types import ChannelID, TimeType, time_from_float
from qctoolkit.pulses.parameters import Parameter, ParameterConstrainer, ParameterConstraint
Expand Down Expand Up @@ -44,7 +44,8 @@ def __init__(self,
identifier: Optional[str] = None,
*,
measurements: Optional[List[MeasurementDeclaration]]=None,
parameter_constraints: Optional[List[Union[str, ParameterConstraint]]]=None) -> None:
parameter_constraints: Optional[List[Union[str, ParameterConstraint]]]=None,
registry: Dict[str, Serializable]=None) -> None:
"""
Args:
expression: The function represented by this FunctionPulseTemplate
Expand All @@ -60,7 +61,7 @@ def __init__(self,
parameter_constraints: A list of parameter constraints forwarded to the
:class:`~`qctoolkit.pulses.measurement.ParameterConstrainer superclass
"""
AtomicPulseTemplate.__init__(self, identifier=identifier, measurements=measurements)
AtomicPulseTemplate.__init__(self, identifier=identifier, measurements=measurements, registry=registry)
ParameterConstrainer.__init__(self, parameter_constraints=parameter_constraints)

self.__expression = ExpressionScalar.make(expression)
Expand Down
18 changes: 12 additions & 6 deletions qctoolkit/pulses/loop_pulse_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@

class LoopPulseTemplate(PulseTemplate):
"""Base class for loop based pulse templates. This class is still abstract and cannot be instantiated."""
def __init__(self, body: PulseTemplate, identifier: Optional[str]=None):
super().__init__(identifier=identifier)
def __init__(self, body: PulseTemplate,
identifier: Optional[str],
registry: Optional[dict]):
super().__init__(identifier=identifier, registry=registry)
self.__body = body

@property
Expand Down Expand Up @@ -109,15 +111,16 @@ def __init__(self,
identifier: Optional[str]=None,
*,
measurements: Optional[Sequence[MeasurementDeclaration]]=None,
parameter_constraints: Optional[Sequence]=None):
parameter_constraints: Optional[Sequence]=None,
registry: Optional[dict]=None):
"""
Args:
body: The loop body. It is expected to have `loop_index` as an parameter
loop_index: Loop index of the for loop
loop_range: Range to loop through
identifier: Used for serialization
"""
LoopPulseTemplate.__init__(self, body=body, identifier=identifier)
LoopPulseTemplate.__init__(self, body=body, identifier=identifier, registry=registry)
MeasurementDefiner.__init__(self, measurements=measurements)
ParameterConstrainer.__init__(self, parameter_constraints=parameter_constraints)

Expand Down Expand Up @@ -291,7 +294,10 @@ class WhileLoopPulseTemplate(LoopPulseTemplate):
during execution as long as a certain condition holds.
"""

def __init__(self, condition: str, body: PulseTemplate, identifier: Optional[str]=None) -> None:
def __init__(self, condition: str,
body: PulseTemplate,
identifier: Optional[str]=None,
registry: Optional[dict]=None) -> None:
"""Create a new LoopPulseTemplate instance.
Args:
Expand All @@ -301,7 +307,7 @@ def __init__(self, condition: str, body: PulseTemplate, identifier: Optional[str
holds.
identifier (str): A unique identifier for use in serialization. (optional)
"""
super().__init__(body=body, identifier=identifier)
super().__init__(body=body, identifier=identifier, registry=registry)
self._condition = condition

def __str__(self) -> str:
Expand Down
5 changes: 3 additions & 2 deletions qctoolkit/pulses/multi_channel_pulse_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,9 @@ def __init__(self,
external_parameters: Optional[Set[str]]=None,
identifier: Optional[str]=None,
parameter_constraints: Optional[List]=None,
measurements: Optional[List[MeasurementDeclaration]]=None) -> None:
AtomicPulseTemplate.__init__(self, identifier=identifier, measurements=measurements)
measurements: Optional[List[MeasurementDeclaration]]=None,
registry: Optional[dict] = None) -> None:
AtomicPulseTemplate.__init__(self, identifier=identifier, measurements=measurements, registry=registry)
ParameterConstrainer.__init__(self, parameter_constraints=parameter_constraints)

self._subtemplates = [st if isinstance(st, PulseTemplate) else MappingPulseTemplate.from_tuple(st) for st in
Expand Down
5 changes: 3 additions & 2 deletions qctoolkit/pulses/point_pulse_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,10 @@ def __init__(self,
*,
parameter_constraints: Optional[List[Union[str, ParameterConstraint]]]=None,
measurements: Optional[List[MeasurementDeclaration]]=None,
identifier=None):
identifier: Optional[str]=None,
registry: Optional[dict]=None):

AtomicPulseTemplate.__init__(self, identifier=identifier, measurements=measurements)
AtomicPulseTemplate.__init__(self, identifier=identifier, measurements=measurements, registry=registry)
ParameterConstrainer.__init__(self, parameter_constraints=parameter_constraints)

self._channels = tuple(channel_names)
Expand Down
11 changes: 7 additions & 4 deletions qctoolkit/pulses/pulse_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,10 @@ class PulseTemplate(Serializable, SequencingElement, metaclass=DocStringABCMeta)
"""

def __init__(self, *,
identifier: Optional[str]) -> None:
super().__init__(identifier)
identifier: Optional[str],
registry: Optional[Dict[str, Serializable]]) -> None:
super().__init__(identifier=identifier,
registry=registry)

@property
@abstractmethod
Expand Down Expand Up @@ -107,8 +109,9 @@ class AtomicPulseTemplate(PulseTemplate, MeasurementDefiner):
"""
def __init__(self, *,
identifier: Optional[str],
measurements: Optional[List[MeasurementDeclaration]]):
PulseTemplate.__init__(self, identifier=identifier)
measurements: Optional[List[MeasurementDeclaration]],
registry: Optional[Dict[str, Serializable]]):
PulseTemplate.__init__(self, identifier=identifier, registry=registry)
MeasurementDefiner.__init__(self, measurements=measurements)

def is_interruptable(self) -> bool:
Expand Down
5 changes: 3 additions & 2 deletions qctoolkit/pulses/pulse_template_parameter_mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ def __init__(self, template: PulseTemplate, *,
measurement_mapping: Optional[Dict[str, str]] = None,
channel_mapping: Optional[Dict[ChannelID, ChannelID]] = None,
parameter_constraints: Optional[List[str]]=None,
allow_partial_parameter_mapping=False):
allow_partial_parameter_mapping: bool=False,
registry: Optional[dict]=None):
"""Standard constructor for the MappingPulseTemplate.
Mappings that are not specified are defaulted to identity mappings. Channels and measurement names of the
Expand All @@ -47,7 +48,7 @@ def __init__(self, template: PulseTemplate, *,
:param parameter_constraints:
:param allow_partial_parameter_mapping:
"""
PulseTemplate.__init__(self, identifier=identifier)
PulseTemplate.__init__(self, identifier=identifier, registry=registry)
ParameterConstrainer.__init__(self, parameter_constraints=parameter_constraints)

if parameter_mapping is None:
Expand Down
5 changes: 3 additions & 2 deletions qctoolkit/pulses/repetition_pulse_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ def __init__(self,
identifier: Optional[str]=None,
*args,
parameter_constraints: Optional[List]=None,
measurements: Optional[List[MeasurementDeclaration]]=None
measurements: Optional[List[MeasurementDeclaration]]=None,
registry: Optional[dict]=None
) -> None:
"""Create a new RepetitionPulseTemplate instance.
Expand All @@ -96,7 +97,7 @@ def __init__(self,
elif args:
TypeError('RepetitionPulseTemplate expects 3 positional arguments, got ' + str(3 + len(args)))

LoopPulseTemplate.__init__(self, identifier=identifier, body=body)
LoopPulseTemplate.__init__(self, identifier=identifier, body=body, registry=registry)
ParameterConstrainer.__init__(self, parameter_constraints=parameter_constraints)
MeasurementDefiner.__init__(self, measurements=measurements)

Expand Down
5 changes: 3 additions & 2 deletions qctoolkit/pulses/sequence_pulse_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ def __init__(self,
external_parameters: Optional[Union[Iterable[str], Set[str]]]=None,
identifier: Optional[str]=None,
parameter_constraints: Optional[List[Union[str, Expression]]]=None,
measurements: Optional[List[MeasurementDeclaration]]=None) -> None:
measurements: Optional[List[MeasurementDeclaration]]=None,
registry: Optional[dict]=None) -> None:
"""Create a new SequencePulseTemplate instance.
Requires a (correctly ordered) list of subtemplates in the form
Expand All @@ -135,7 +136,7 @@ def __init__(self,
SequencePulseTemplate. Deprecated.
identifier (str): A unique identifier for use in serialization. (optional)
"""
PulseTemplate.__init__(self, identifier=identifier)
PulseTemplate.__init__(self, identifier=identifier, registry=registry)
ParameterConstrainer.__init__(self, parameter_constraints=parameter_constraints)
MeasurementDefiner.__init__(self, measurements=measurements)

Expand Down
5 changes: 3 additions & 2 deletions qctoolkit/pulses/table_pulse_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,8 @@ def __init__(self, entries: Dict[ChannelID, Sequence[EntryInInit]],
*,
parameter_constraints: Optional[List[Union[str, ParameterConstraint]]]=None,
measurements: Optional[List[MeasurementDeclaration]]=None,
consistency_check=True):
consistency_check: bool=True,
registry: Optional[dict]=None):
"""
Construct a `TablePulseTemplate` from a dict which maps channels to their entries. By default the consistency
of the provided entries is checked. There are two static functions for convenience construction: from_array and
Expand All @@ -186,7 +187,7 @@ def __init__(self, entries: Dict[ChannelID, Sequence[EntryInInit]],
measurements: Measurement declaration list that is forwarded to the MeasurementDefiner superclass
consistency_check: If True the consistency of the times will be checked on construction as far as possible
"""
AtomicPulseTemplate.__init__(self, identifier=identifier, measurements=measurements)
AtomicPulseTemplate.__init__(self, identifier=identifier, measurements=measurements, registry=registry)
ParameterConstrainer.__init__(self, parameter_constraints=parameter_constraints)

self._entries = dict((ch, list()) for ch in entries.keys())
Expand Down
25 changes: 16 additions & 9 deletions qctoolkit/serialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import json
import weakref
import warnings
import gc

from qctoolkit.utils.types import DocStringABCMeta

Expand Down Expand Up @@ -316,7 +317,7 @@ def __new__(mcs, name, bases, dct):
return cls


default_pulse_registration = weakref.WeakValueDictionary()
default_pulse_registry = weakref.WeakValueDictionary()


class Serializable(metaclass=SerializableMeta):
Expand All @@ -339,30 +340,36 @@ class Serializable(metaclass=SerializableMeta):
type_identifier_name = '#type'
identifier_name = '#identifier'

def __init__(self, identifier: Optional[str]=None, registration: weakref.WeakValueDictionary=None) -> None:
def __init__(self, identifier: Optional[str]=None, registry: Optional[dict]=None) -> None:
"""Initialize a Serializable.
Args:
identifier: An optional, non-empty identifier for this Serializable.
If set, this Serializable will always be stored as a separate data item and never
be embedded.
registry: An optional dict where the Serializable is registered. If None, it gets registered in the
default_pulse_registry.
Raises:
ValueError: If identifier is the empty string
"""
super().__init__()

if registration is None:
registration = default_pulse_registration
if registry is None:
registry = default_pulse_registry

if identifier == '':
raise ValueError("Identifier must not be empty.")
self.__identifier = identifier

if identifier and registration:
if identifier in registration:
raise RuntimeError('Pulse with name already exists', identifier)
else:
registration[identifier] = self
if identifier:
if identifier in registry:
# trigger garbage collection in case the registered object isn't referenced anymore
gc.collect(2)

if identifier in registry:
raise RuntimeError('Pulse with name already exists', identifier)

registry[identifier] = self

@property
def identifier(self) -> Optional[str]:
Expand Down
2 changes: 1 addition & 1 deletion tests/pulses/function_pulse_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ def test_serializer_integration_old(self):
channel='A',
measurements=self.meas_list,
parameter_constraints=self.constraints,
identifier='my_tpt')
identifier='my_tpt', registry=dict())
serializer = Serializer(DummyStorageBackend())
serializer.serialize(before)
after = serializer.deserialize('my_tpt')
Expand Down
1 change: 1 addition & 0 deletions tests/pulses/loop_pulse_template_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
class DummyLoopPulseTemplate(LoopPulseTemplate):
pass
DummyLoopPulseTemplate.__abstractmethods__ = set()
DummyLoopPulseTemplate.__init__ = lambda self, body: LoopPulseTemplate.__init__(self, body, None, None)


class LoopPulseTemplateTests(unittest.TestCase):
Expand Down
4 changes: 2 additions & 2 deletions tests/pulses/multi_channel_pulse_template_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,11 +321,11 @@ def make_kwargs(self):
'parameter_constraints': [str(ParameterConstraint('ilse>2')), str(ParameterConstraint('k>foo'))]
}

def make_instance(self, identifier=None):
def make_instance(self, identifier=None, registry=None):
kwargs = self.make_kwargs()
subtemplates = kwargs['subtemplates']
del kwargs['subtemplates']
return self.class_to_test(identifier=identifier, *subtemplates, **kwargs)
return self.class_to_test(identifier=identifier, *subtemplates, **kwargs, registry=registry)

def assert_equal_instance(self, lhs: AtomicMultiChannelPulseTemplate, rhs: AtomicMultiChannelPulseTemplate):
self.assertIsInstance(lhs, AtomicMultiChannelPulseTemplate)
Expand Down
5 changes: 4 additions & 1 deletion tests/pulses/point_pulse_template_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,8 @@ def setUp(self) -> None:
self.measurements = [('m', 1, 1), ('foo', 'z', 'o')]
self.template = PointPulseTemplate(time_point_tuple_list=self.entries, channel_names=[0, 'A'],
measurements=self.measurements,
identifier='foo', parameter_constraints=['ilse>2', 'k>foo'])
identifier='foo', parameter_constraints=['ilse>2', 'k>foo'],
registry=dict())
self.maxDiff = None

def test_get_serialization_data_old(self) -> None:
Expand Down Expand Up @@ -286,6 +287,8 @@ def test_deserialize_old(self) -> None:
self.assertEqual(template.parameter_constraints, self.template.parameter_constraints)

def test_serializer_integration_old(self):
registry = dict()

# test for deprecated version during transition period, remove after final switch
with self.assertWarnsRegex(DeprecationWarning, "deprecated",
msg="PointPT does not issue warning for old serialization routines."):
Expand Down
10 changes: 6 additions & 4 deletions tests/pulses/pulse_template_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ def __init__(self, identifier=None,
defined_channels=None,
duration=None,
parameter_names=None,
measurement_names=None):
super().__init__(identifier=identifier)
measurement_names=None,
registry=None):
super().__init__(identifier=identifier, registry=registry)

self._defined_channels = defined_channels
self._duration = duration
Expand Down Expand Up @@ -82,8 +83,9 @@ def is_interruptable(self) -> bool:
return super().is_interruptable()

def __init__(self, *, waveform: Waveform=None, duration: Expression=None, measurements=None,
identifier: Optional[str]=None) -> None:
super().__init__(identifier=identifier, measurements=measurements)
identifier: Optional[str]=None,
registry=None) -> None:
super().__init__(identifier=identifier, measurements=measurements, registry=registry)
self.waveform = waveform
self._duration = duration

Expand Down
10 changes: 6 additions & 4 deletions tests/pulses/sequence_pulse_template_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,11 +186,11 @@ def make_kwargs(self):
'measurements': [('m', 0, 1)]
}

def make_instance(self, identifier=None):
def make_instance(self, identifier=None, registry=None):
kwargs = self.make_kwargs()
subtemplates = kwargs['subtemplates']
del kwargs['subtemplates']
return self.class_to_test(identifier=identifier, *subtemplates, **kwargs)
return self.class_to_test(identifier=identifier, *subtemplates, **kwargs, registry=registry)

def assert_equal_instance(self, lhs: SequencePulseTemplate, rhs: SequencePulseTemplate):
self.assertIsInstance(lhs, SequencePulseTemplate)
Expand All @@ -207,7 +207,8 @@ def setUp(self) -> None:
('albert', 'voltage')]},
parameter_constraints=['albert<9.1'],
measurements=[('mw_foo','hugo','albert')],
identifier='foo')
identifier='foo',
registry=dict())

self.foo_param_mappings = dict(hugo='ilse', albert='albert', voltage='voltage')
self.foo_meas_mappings = dict(mw_foo='mw_bar')
Expand All @@ -219,7 +220,8 @@ def test_get_serialization_data_old(self) -> None:
dummy1 = DummyPulseTemplate()
dummy2 = DummyPulseTemplate()

sequence = SequencePulseTemplate(dummy1, dummy2, parameter_constraints=['a<b'], measurements=[('m', 0, 1)])
sequence = SequencePulseTemplate(dummy1, dummy2, parameter_constraints=['a<b'], measurements=[('m', 0, 1)],
registry=dict())
serializer = DummySerializer(serialize_callback=lambda x: str(x))

expected_data = dict(
Expand Down
5 changes: 3 additions & 2 deletions tests/pulses/sequencing_dummies.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,8 +298,9 @@ def __init__(self,
measurement_names: Set[str] = set(),
measurements: list=list(),
integrals: Dict[ChannelID, ExpressionScalar]={'default': ExpressionScalar(0)},
identifier=None) -> None:
super().__init__(identifier=identifier, measurements=measurements)
identifier=None,
registry=None) -> None:
super().__init__(identifier=identifier, measurements=measurements, registry=registry)
self.requires_stop_ = requires_stop
self.requires_stop_arguments = []

Expand Down

0 comments on commit bb9f405

Please sign in to comment.