diff --git a/qupulse/program/linspace.py b/qupulse/program/linspace.py index a52aa91e..0bfe7936 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: Optional['ForLoopPT']=None) -> 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 9d6ac573..6f5651cb 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: Optional['ForLoopPT']=None) -> 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 a3692e4d..6cf0df0a 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: 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 `.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/loop_pulse_template.py b/qupulse/pulses/loop_pulse_template.py index 86b5589c..b97dd8ff 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, diff --git a/qupulse/pulses/pulse_template.py b/qupulse/pulses/pulse_template.py index 719ba220..7a9c0514 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: