Beispiel #1
0
    def _internal_create_program(
            self, *, scope: Scope, measurement_mapping: Dict[str,
                                                             Optional[str]],
            channel_mapping: Dict[ChannelID, Optional[ChannelID]],
            global_transformation: Optional[Transformation],
            to_single_waveform: Set[Union[str, 'PulseTemplate']],
            parent_loop: Loop) -> None:
        """Parameter constraints are validated in build_waveform because build_waveform is guaranteed to be called
        during sequencing"""
        ### 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"

        waveform = self.build_waveform(parameters=scope,
                                       channel_mapping=channel_mapping)
        if waveform:
            measurements = self.get_measurement_windows(
                parameters=scope, measurement_mapping=measurement_mapping)

            if global_transformation:
                waveform = TransformingWaveform(waveform,
                                                global_transformation)

            parent_loop.add_measurements(measurements=measurements)
            parent_loop.append_child(waveform=waveform)
    def _internal_create_program(
            self, *, scope: Scope, measurement_mapping: Dict[str,
                                                             Optional[str]],
            channel_mapping: Dict[ChannelID, Optional[ChannelID]],
            global_transformation: Optional[Transformation],
            to_single_waveform: Set[Union[str, 'PulseTemplate']],
            parent_loop: 'Loop'):
        """The operation is applied by modifying the transformation the pulse template operand sees."""
        if not scope.get_volatile_parameters().keys().isdisjoint(
                self._scalar_operand_parameters):
            raise NotImplementedError(
                'The scalar operand of arithmetic pulse template cannot be volatile'
            )

        # put arithmetic into transformation
        inner_transformation = self._get_transformation(
            parameters=scope, channel_mapping=channel_mapping)

        transformation = inner_transformation.chain(global_transformation)

        self._pulse_template._create_program(
            scope=scope,
            measurement_mapping=measurement_mapping,
            channel_mapping=channel_mapping,
            global_transformation=transformation,
            to_single_waveform=to_single_waveform,
            parent_loop=parent_loop)
Beispiel #3
0
    def _body_scope_generator(self,
                              scope: Scope,
                              forward=True) -> Iterator[Scope]:
        loop_range = self._loop_range.to_range(scope)

        loop_range = loop_range if forward else reversed(loop_range)
        loop_index_name = self._loop_index

        for loop_index_value in loop_range:
            yield scope.overwrite({loop_index_name: loop_index_value})
Beispiel #4
0
    def validate_scope(self, scope: Scope):
        volatile = scope.get_volatile_parameters().keys()

        for constraint in self._parameter_constraints:
            if not constraint.is_fulfilled(scope, volatile=volatile):
                constrained_parameters = {
                    parameter_name: scope[parameter_name]
                    for parameter_name in constraint.affected_parameters
                }
                raise ParameterConstraintViolation(constraint,
                                                   constrained_parameters)
Beispiel #5
0
    def _create_program(self, *, scope: Scope,
                        measurement_mapping: Dict[str, Optional[str]],
                        channel_mapping: Dict[ChannelID, Optional[ChannelID]],
                        global_transformation: Optional[Transformation],
                        to_single_waveform: Set[Union[str, 'PulseTemplate']],
                        parent_loop: Loop):
        """Generic part of create program. This method handles to_single_waveform and the configuration of the
        transformer."""
        if self.identifier in to_single_waveform or self in to_single_waveform:
            root = Loop()

            if not scope.get_volatile_parameters().keys().isdisjoint(
                    self.parameter_names):
                raise NotImplementedError(
                    'A pulse template that has volatile parameters cannot be transformed into a '
                    'single waveform yet.')

            self._internal_create_program(
                scope=scope,
                measurement_mapping=measurement_mapping,
                channel_mapping=channel_mapping,
                global_transformation=None,
                to_single_waveform=to_single_waveform,
                parent_loop=root)

            waveform = to_waveform(root)

            if global_transformation:
                waveform = TransformingWaveform(waveform,
                                                global_transformation)

            # convert the nicely formatted measurement windows back into the old format again :(
            measurements = root.get_measurement_windows()
            measurement_window_list = []
            for measurement_name, (begins, lengths) in measurements.items():
                measurement_window_list.extend(
                    zip(itertools.repeat(measurement_name), begins, lengths))

            parent_loop.add_measurements(measurement_window_list)
            parent_loop.append_child(waveform=waveform)

        else:
            self._internal_create_program(
                scope=scope,
                measurement_mapping=measurement_mapping,
                channel_mapping=channel_mapping,
                to_single_waveform=to_single_waveform,
                global_transformation=global_transformation,
                parent_loop=parent_loop)
Beispiel #6
0
    def _internal_create_program(
            self, *, scope: Scope, measurement_mapping: Dict[str,
                                                             Optional[str]],
            channel_mapping: Dict[ChannelID, Optional[ChannelID]],
            global_transformation: Optional['Transformation'],
            to_single_waveform: Set[Union[str, 'PulseTemplate']],
            parent_loop: Loop) -> None:
        self.validate_scope(scope)

        repetition_count = max(0, self.get_repetition_count_value(scope))

        # todo (2018-07-19): could in some circumstances possibly just multiply subprogram repetition count?
        # could be tricky if any repetition count is volatile ? check later and optimize if necessary
        if repetition_count > 0:
            if scope.get_volatile_parameters().keys(
            ) & self.repetition_count.variables:
                repetition_definition = VolatileRepetitionCount(
                    self.repetition_count, scope)
                assert int(repetition_definition) == repetition_count
            else:
                repetition_definition = repetition_count

            repj_loop = Loop(repetition_count=repetition_definition)
            self.body._create_program(
                scope=scope,
                measurement_mapping=measurement_mapping,
                channel_mapping=channel_mapping,
                global_transformation=global_transformation,
                to_single_waveform=to_single_waveform,
                parent_loop=repj_loop)
            if repj_loop.waveform is not None or len(repj_loop.children) > 0:
                measurements = self.get_measurement_windows(
                    scope, measurement_mapping)
                if measurements:
                    parent_loop.add_measurements(measurements)

                parent_loop.append_child(loop=repj_loop)