From b1c55b4dead8bb533651ab1bc7731d046619f0c6 Mon Sep 17 00:00:00 2001 From: Selene Lab Date: Sun, 27 Oct 2024 18:59:38 +0100 Subject: [PATCH] pad all atomic subtemplates --- qupulse/pulses/arithmetic_pulse_template.py | 9 ++++- qupulse/pulses/loop_pulse_template.py | 12 ++++-- qupulse/pulses/mapping_pulse_template.py | 11 ++++-- .../pulses/multi_channel_pulse_template.py | 19 ++++++++-- qupulse/pulses/pulse_template.py | 38 ++++++++++++++----- qupulse/pulses/repetition_pulse_template.py | 12 ++++-- qupulse/pulses/sequence_pulse_template.py | 8 +++- .../pulses/time_reversal_pulse_template.py | 10 ++++- 8 files changed, 92 insertions(+), 27 deletions(-) diff --git a/qupulse/pulses/arithmetic_pulse_template.py b/qupulse/pulses/arithmetic_pulse_template.py index eedfce20..69f0a9bf 100644 --- a/qupulse/pulses/arithmetic_pulse_template.py +++ b/qupulse/pulses/arithmetic_pulse_template.py @@ -6,7 +6,7 @@ import sympy -from qupulse.expressions import ExpressionScalar, ExpressionLike +from qupulse.expressions import ExpressionScalar, ExpressionLike, Expression from qupulse.serialization import Serializer, PulseRegistryType from qupulse.parameter_scope import Scope @@ -538,7 +538,12 @@ def get_measurement_windows(self, def _is_atomic(self): return self._pulse_template._is_atomic() - + + def pad_all_atomic_subtemplates_to(self, + to_new_duration: Callable[[Expression], ExpressionLike]) -> 'PulseTemplate': + + self._pulse_template = self._pulse_template.pad_all_atomic_subtemplates_to(to_new_duration) + def try_operation(lhs: Union[PulseTemplate, ExpressionLike, Mapping[ChannelID, ExpressionLike]], op: str, diff --git a/qupulse/pulses/loop_pulse_template.py b/qupulse/pulses/loop_pulse_template.py index d1a4713d..712f7d9d 100644 --- a/qupulse/pulses/loop_pulse_template.py +++ b/qupulse/pulses/loop_pulse_template.py @@ -4,7 +4,7 @@ import functools import itertools from abc import ABC -from typing import Dict, Set, Optional, Any, Union, Tuple, Iterator, Sequence, cast, Mapping +from typing import Dict, Set, Optional, Any, Union, Tuple, Iterator, Sequence, cast, Mapping, Callable import warnings from numbers import Number @@ -16,7 +16,7 @@ from qupulse.program import ProgramBuilder -from qupulse.expressions import ExpressionScalar, ExpressionVariableMissingException, Expression +from qupulse.expressions import ExpressionScalar, ExpressionVariableMissingException, Expression, ExpressionLike from qupulse.utils import checked_int_cast, cached_property from qupulse.pulses.parameters import InvalidParameterNameException, ParameterConstrainer, ParameterNotProvidedException from qupulse.pulses.pulse_template import PulseTemplate, ChannelID, AtomicPulseTemplate @@ -241,7 +241,13 @@ def final_values(self) -> Dict[ChannelID, ExpressionScalar]: for ch, value in values.items(): values[ch] = ExpressionScalar(value.underlying_expression.subs(self._loop_index, final_idx)) return values - + + def pad_all_atomic_subtemplates_to(self, + to_new_duration: Callable[[Expression], ExpressionLike]) -> 'ForLoopPulseTemplate': + self.__body = self.body.pad_all_atomic_subtemplates_to(to_new_duration) + self.__dict__.pop('duration', None) + return self + class LoopIndexNotUsedException(Exception): def __init__(self, loop_index: str, body_parameter_names: Set[str]): diff --git a/qupulse/pulses/mapping_pulse_template.py b/qupulse/pulses/mapping_pulse_template.py index 07e7d102..1275ee74 100644 --- a/qupulse/pulses/mapping_pulse_template.py +++ b/qupulse/pulses/mapping_pulse_template.py @@ -1,10 +1,10 @@ -from typing import Optional, Set, Dict, Union, List, Any, Tuple, Mapping +from typing import Optional, Set, Dict, Union, List, Any, Tuple, Mapping, Callable import itertools import numbers import collections from qupulse.utils.types import ChannelID, FrozenDict, FrozenMapping -from qupulse.expressions import Expression, ExpressionScalar +from qupulse.expressions import Expression, ExpressionScalar, ExpressionLike from qupulse.parameter_scope import Scope, MappedScope from qupulse.pulses.pulse_template import PulseTemplate, MappingTuple from qupulse.pulses.parameters import ParameterNotProvidedException, ParameterConstrainer @@ -352,7 +352,12 @@ def initial_values(self) -> Dict[ChannelID, ExpressionScalar]: @property def final_values(self) -> Dict[ChannelID, ExpressionScalar]: return self._apply_mapping_to_inner_channel_dict(self.__template.final_values) - + + def pad_all_atomic_subtemplates_to(self, + to_new_duration: Callable[[Expression], ExpressionLike]) -> 'PulseTemplate': + + self.__template = self.template.pad_all_atomic_subtemplates_to(to_new_duration) + return self class MissingMappingException(Exception): """Indicates that no mapping was specified for some parameter declaration of a diff --git a/qupulse/pulses/multi_channel_pulse_template.py b/qupulse/pulses/multi_channel_pulse_template.py index 6b76bb49..83c4a363 100644 --- a/qupulse/pulses/multi_channel_pulse_template.py +++ b/qupulse/pulses/multi_channel_pulse_template.py @@ -7,7 +7,7 @@ - ParallelChannelPulseTemplate: A pulse template to add channels to an existing pulse template. """ -from typing import Dict, List, Optional, Any, AbstractSet, Union, Set, Sequence, Mapping +from typing import Dict, List, Optional, Any, AbstractSet, Union, Set, Sequence, Mapping, Callable import numbers import warnings @@ -215,7 +215,14 @@ def final_values(self) -> Dict[ChannelID, ExpressionScalar]: for subtemplate in self._subtemplates: values.update(subtemplate.final_values) return values - + + def pad_all_atomic_subtemplates_to(self, + to_new_duration: Callable[[Expression], ExpressionLike]) -> 'PulseTemplate': + + for i,subtemplate in enumerate(self._subtemplates): + self._subtemplates[i] = subtemplate.pad_all_atomic_subtemplates_to(to_new_duration) + return self + class ParallelChannelPulseTemplate(PulseTemplate): def __init__(self, @@ -352,7 +359,13 @@ def with_parallel_channels(self, values: Mapping[ChannelID, ExpressionLike]) -> def _is_atomic(self) -> bool: return self._template._is_atomic() - + + def pad_all_atomic_subtemplates_to(self, + to_new_duration: Callable[[Expression], ExpressionLike]) -> 'PulseTemplate': + + self._template = self.template.pad_all_atomic_subtemplates_to(to_new_duration) + return self + ParallelConstantChannelPulseTemplate = ParallelChannelPulseTemplate diff --git a/qupulse/pulses/pulse_template.py b/qupulse/pulses/pulse_template.py index fb9f161f..5be17d6c 100644 --- a/qupulse/pulses/pulse_template.py +++ b/qupulse/pulses/pulse_template.py @@ -376,7 +376,7 @@ def with_appended(self, *appended: 'PulseTemplate'): return self def pad_to(self, to_new_duration: Union[ExpressionLike, Callable[[Expression], ExpressionLike]], - as_single_wf: bool = True, + as_single_wf: bool = False, pt_kwargs: Mapping[str, Any] = {}) -> 'PulseTemplate': """Pad this pulse template to the given duration. The target duration can be numeric, symbolic or a callable that returns a new duration from the current @@ -405,7 +405,7 @@ def pad_to(self, to_new_duration: Union[ExpressionLike, Callable[[Expression], E Returns: A pulse template that has the duration given by ``to_new_duration``. - self if ConstantPT, + XXX# self if ConstantPT, else SingleWFTimeExtensionPulseTemplate if as_single_wf, else SequencePT """ @@ -418,12 +418,13 @@ def pad_to(self, to_new_duration: Union[ExpressionLike, Callable[[Expression], E new_duration = ExpressionScalar(to_new_duration) pad_duration = new_duration - current_duration - #shortcut - if isinstance(self,ConstantPT): - if pt_kwargs: - raise NotImplementedError() - self._duration = new_duration - return self + #maybe leads to inconsistencies if self may be returned + # #shortcut + # if isinstance(self,ConstantPT): + # if pt_kwargs: + # raise NotImplementedError() + # self._duration = new_duration + # return self if as_single_wf: return SingleWFTimeExtensionPulseTemplate(self, new_duration, **pt_kwargs) @@ -436,7 +437,16 @@ def pad_to(self, to_new_duration: Union[ExpressionLike, Callable[[Expression], E return SequencePT(self, pad_pt, **pt_kwargs) else: return self @ pad_pt - + + # @abstractmethod + def pad_all_atomic_subtemplates_to(self, + to_new_duration: Callable[[Expression], ExpressionLike]) -> 'PulseTemplate': + """pad ll atomic subtemplates to a new duration determiend from callable + to_new_duration, e.g. from qupulse.utils.to_next_multiple for waveform + granularity. + """ + raise NotImplementedError() + def __format__(self, format_spec: str): if format_spec == '': format_spec = self._DEFAULT_FORMAT_SPEC @@ -611,7 +621,15 @@ def final_values(self) -> Dict[ChannelID, ExpressionScalar]: for ch, value in values.items(): values[ch] = value.evaluate_symbolic({self._AS_EXPRESSION_TIME: self.duration}) return values - + + def pad_to(self, to_new_duration: Union[ExpressionLike, Callable[[Expression], ExpressionLike]], + pt_kwargs: Mapping[str, Any] = {}) -> 'PulseTemplate': + return super().pad_to(to_new_duration,as_single_wf=True,pt_kwargs=pt_kwargs) + + def pad_all_atomic_subtemplates_to(self, + to_new_duration: Callable[[Expression], ExpressionLike]) -> 'PulseTemplate': + return self.pad_to(to_new_duration) + class DoubleParameterNameException(Exception): diff --git a/qupulse/pulses/repetition_pulse_template.py b/qupulse/pulses/repetition_pulse_template.py index 85bd4cfd..16424905 100644 --- a/qupulse/pulses/repetition_pulse_template.py +++ b/qupulse/pulses/repetition_pulse_template.py @@ -1,7 +1,7 @@ """This module defines RepetitionPulseTemplate, a higher-order hierarchical pulse template that represents the n-times repetition of another PulseTemplate.""" -from typing import Dict, List, AbstractSet, Optional, Union, Any, Mapping, cast +from typing import Dict, List, AbstractSet, Optional, Union, Any, Mapping, cast, Callable from numbers import Real from warnings import warn @@ -13,7 +13,7 @@ from qupulse.parameter_scope import Scope from qupulse.utils.types import ChannelID -from qupulse.expressions import ExpressionScalar +from qupulse.expressions import ExpressionScalar, Expression, ExpressionLike from qupulse.utils import checked_int_cast from qupulse.pulses.pulse_template import PulseTemplate from qupulse.pulses.loop_pulse_template import LoopPulseTemplate @@ -180,7 +180,13 @@ def initial_values(self) -> Dict[ChannelID, ExpressionScalar]: @property def final_values(self) -> Dict[ChannelID, ExpressionScalar]: return self.body.final_values - + + def pad_all_atomic_subtemplates_to(self, + to_new_duration: Callable[[Expression], ExpressionLike]) -> 'PulseTemplate': + + self.__body = self.body.pad_all_atomic_subtemplates_to(to_new_duration) + return self + class ParameterNotIntegerException(Exception): """Indicates that the value of the parameter given as repetition count was not an integer.""" diff --git a/qupulse/pulses/sequence_pulse_template.py b/qupulse/pulses/sequence_pulse_template.py index 5107bb10..503957b9 100644 --- a/qupulse/pulses/sequence_pulse_template.py +++ b/qupulse/pulses/sequence_pulse_template.py @@ -17,7 +17,7 @@ from qupulse.pulses.mapping_pulse_template import MappingPulseTemplate, MappingTuple from qupulse.program.waveforms import SequenceWaveform from qupulse.pulses.measurement import MeasurementDeclaration, MeasurementDefiner -from qupulse.expressions import Expression, ExpressionScalar +from qupulse.expressions import Expression, ExpressionScalar, ExpressionLike __all__ = ["SequencePulseTemplate"] @@ -194,3 +194,9 @@ def initial_values(self) -> Dict[ChannelID, ExpressionScalar]: def final_values(self) -> Dict[ChannelID, ExpressionScalar]: return self.__subtemplates[-1].final_values + def pad_all_atomic_subtemplates_to(self, + to_new_duration: Callable[[Expression], ExpressionLike]) -> 'PulseTemplate': + + for i,sub in enumerate(self.__subtemplates): + self.__subtemplates[i] = sub.pad_all_atomic_subtemplates_to(to_new_duration) + return self \ No newline at end of file diff --git a/qupulse/pulses/time_reversal_pulse_template.py b/qupulse/pulses/time_reversal_pulse_template.py index 35a1884b..6a984a92 100644 --- a/qupulse/pulses/time_reversal_pulse_template.py +++ b/qupulse/pulses/time_reversal_pulse_template.py @@ -1,10 +1,10 @@ -from typing import Optional, Set, Dict, Union +from typing import Optional, Set, Dict, Union, Callable from qupulse import ChannelID from qupulse.program.loop import Loop from qupulse.program.waveforms import Waveform from qupulse.serialization import PulseRegistryType -from qupulse.expressions import ExpressionScalar +from qupulse.expressions import ExpressionScalar, Expression, ExpressionLike from qupulse.pulses.pulse_template import PulseTemplate @@ -68,3 +68,9 @@ def get_serialization_data(self, serializer=None): def _is_atomic(self) -> bool: return self._inner._is_atomic() + + def pad_all_atomic_subtemplates_to(self, + to_new_duration: Callable[[Expression], ExpressionLike]) -> 'PulseTemplate': + self._inner = self._inner.pad_all_atomic_subtemplates_to(to_new_duration) + return self + \ No newline at end of file