From bc5fdd638d9679b5ae85da13483477eb3edfe2ce Mon Sep 17 00:00:00 2001 From: Nomos11 <82180697+Nomos11@users.noreply.github.com> Date: Wed, 30 Jul 2025 11:08:04 +0200 Subject: [PATCH 1/2] other compatibility hacks remaining from experiment branch --- qupulse/program/linspace.py | 3 ++- qupulse/program/loop.py | 3 ++- qupulse/program/protocol.py | 9 ++++++++- qupulse/pulses/pulse_template.py | 15 ++++++++++++++- 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/qupulse/program/linspace.py b/qupulse/program/linspace.py index a52aa91ec..bf6f87a09 100644 --- a/qupulse/program/linspace.py +++ b/qupulse/program/linspace.py @@ -194,7 +194,7 @@ def _root(self): def _get_rng(self, idx_name: str) -> range: return self._get_ranges()[idx_name] - def inner_scope(self, scope: Scope) -> Scope: + def inner_scope(self, scope: Scope, pt_obj: 'ForLoopPT') -> Scope: """This function is necessary to inject program builder specific parameter implementations into the build process.""" if self._ranges: @@ -277,6 +277,7 @@ def new_subprogram(self, global_transformation: 'Transformation' = None) -> Cont raise NotImplementedError('Not implemented yet (postponed)') def with_iteration(self, index_name: str, rng: range, + pt_obj: 'ForLoopPT', measurements: Optional[Sequence[MeasurementWindow]] = None) -> Iterable['ProgramBuilder']: if len(rng) == 0: return diff --git a/qupulse/program/loop.py b/qupulse/program/loop.py index 9d6ac573c..5ff768603 100644 --- a/qupulse/program/loop.py +++ b/qupulse/program/loop.py @@ -773,7 +773,7 @@ def __init__(self): self._stack: List[StackFrame] = [StackFrame(self._root, None)] - def inner_scope(self, scope: Scope) -> Scope: + def inner_scope(self, scope: Scope, pt_obj: 'ForLoopPT') -> Scope: local_vars = self._stack[-1].iterating if local_vars is None: return scope @@ -808,6 +808,7 @@ def with_repetition(self, repetition_count: RepetitionCount, self._try_append(repetition_loop, measurements) def with_iteration(self, index_name: str, rng: range, + pt_obj: 'ForLoopPT', measurements: Optional[Sequence[MeasurementWindow]] = None) -> Iterable['ProgramBuilder']: with self.with_sequence(measurements): top_frame = self._stack[-1] diff --git a/qupulse/program/protocol.py b/qupulse/program/protocol.py index a3692e4d1..5c1b50d18 100644 --- a/qupulse/program/protocol.py +++ b/qupulse/program/protocol.py @@ -42,7 +42,9 @@ class ProgramBuilder(Protocol): """ @abstractmethod - def inner_scope(self, scope: Scope) -> Scope: + def inner_scope(self, scope: Scope, + pt_obj: 'ForLoopPT', #hack this in for now. + ) -> Scope: """This function is part of the iteration protocol and necessary to inject program builder specific parameter implementations into the build process. :py:meth:`.ProgramBuilder.with_iteration` and `.ProgramBuilder.with_iteration` callers *must* call this function inside the iteration. @@ -128,6 +130,7 @@ def new_subprogram(self, global_transformation: 'Transformation' = None) -> Cont @abstractmethod def with_iteration(self, index_name: str, rng: range, + pt_obj: 'ForLoopPT', measurements: Optional[Sequence[MeasurementWindow]] = None) -> Iterable['ProgramBuilder']: """Create an iterable that represent the body of the iteration. This can be an iterable with an element for each step in the iteration or a single object that represents the complete iteration. @@ -153,3 +156,7 @@ def to_program(self) -> Optional[Program]: Returns: A program implementation. None if nothing was added to this program builder. """ + + def evaluate_nested_stepping(self, scope: Scope, parameter_names: set[str]) -> bool: + """A hacky way to include extra sequencing opportunities for some Builders""" + return False \ No newline at end of file diff --git a/qupulse/pulses/pulse_template.py b/qupulse/pulses/pulse_template.py index 719ba220f..7a9c05149 100644 --- a/qupulse/pulses/pulse_template.py +++ b/qupulse/pulses/pulse_template.py @@ -701,7 +701,20 @@ def _internal_create_program(self, *, ### current behavior (same as previously): only adds EXEC Loop and measurements if a waveform exists. ### measurements are directly added to parent_loop (to reflect behavior of Sequencer + MultiChannelProgram) assert not scope.get_volatile_parameters().keys() & self.parameter_names, "AtomicPT cannot be volatile" - + + if program_builder.evaluate_nested_stepping(scope,self.parameter_names): + measurements = self.get_measurement_windows(parameters=scope,measurement_mapping=measurement_mapping) + program_builder.measure(measurements) + program_builder.dispatch_to_stepped_wf_or_hold(build_func=self.build_waveform, + build_parameters=scope, + parameter_names=self.parameter_names, + channel_mapping=channel_mapping, + #measurements + global_transformation=global_transformation, + _pow_2_divisor=self._pow_2_divisor + ) + return + waveform = self.build_waveform(parameters=scope, channel_mapping=channel_mapping) if waveform: From f903de7b411758b2dd6e5a58fb0b813ed43d7143 Mon Sep 17 00:00:00 2001 From: Nomos11 <82180697+Nomos11@users.noreply.github.com> Date: Wed, 30 Jul 2025 12:21:24 +0200 Subject: [PATCH 2/2] optional looppt --- qupulse/program/linspace.py | 2 +- qupulse/program/loop.py | 2 +- qupulse/program/protocol.py | 2 +- qupulse/pulses/loop_pulse_template.py | 3 ++- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/qupulse/program/linspace.py b/qupulse/program/linspace.py index bf6f87a09..0bfe7936e 100644 --- a/qupulse/program/linspace.py +++ b/qupulse/program/linspace.py @@ -194,7 +194,7 @@ def _root(self): def _get_rng(self, idx_name: str) -> range: return self._get_ranges()[idx_name] - def inner_scope(self, scope: Scope, pt_obj: 'ForLoopPT') -> Scope: + def inner_scope(self, scope: Scope, pt_obj: Optional['ForLoopPT']=None) -> Scope: """This function is necessary to inject program builder specific parameter implementations into the build process.""" if self._ranges: diff --git a/qupulse/program/loop.py b/qupulse/program/loop.py index 5ff768603..6f5651cb6 100644 --- a/qupulse/program/loop.py +++ b/qupulse/program/loop.py @@ -773,7 +773,7 @@ def __init__(self): self._stack: List[StackFrame] = [StackFrame(self._root, None)] - def inner_scope(self, scope: Scope, pt_obj: 'ForLoopPT') -> Scope: + def inner_scope(self, scope: Scope, pt_obj: Optional['ForLoopPT']=None) -> Scope: local_vars = self._stack[-1].iterating if local_vars is None: return scope diff --git a/qupulse/program/protocol.py b/qupulse/program/protocol.py index 5c1b50d18..6cf0df0a4 100644 --- a/qupulse/program/protocol.py +++ b/qupulse/program/protocol.py @@ -43,7 +43,7 @@ class ProgramBuilder(Protocol): @abstractmethod def inner_scope(self, scope: Scope, - pt_obj: 'ForLoopPT', #hack this in for now. + pt_obj: Optional['ForLoopPT'] = None, #hack this in for now. ) -> Scope: """This function is part of the iteration protocol and necessary to inject program builder specific parameter implementations into the build process. :py:meth:`.ProgramBuilder.with_iteration` and diff --git a/qupulse/pulses/loop_pulse_template.py b/qupulse/pulses/loop_pulse_template.py index 86b5589ce..b97dd8ff9 100644 --- a/qupulse/pulses/loop_pulse_template.py +++ b/qupulse/pulses/loop_pulse_template.py @@ -185,8 +185,9 @@ def _internal_create_program(self, *, measurements = self.get_measurement_windows(scope, measurement_mapping) for iteration_program_builder in program_builder.with_iteration(loop_index_name, loop_range, + self, measurements=measurements): - self.body._create_program(scope=iteration_program_builder.inner_scope(scope), + self.body._create_program(scope=iteration_program_builder.inner_scope(scope,self), measurement_mapping=measurement_mapping, channel_mapping=channel_mapping, global_transformation=global_transformation,