Пример #1
0
    def __init__(self, sub_waveforms: List[Waveform]) -> None:
        """Create a new MultiChannelWaveform instance.
        Use `MultiChannelWaveform.from_parallel` for optimal construction.

        Requires a list of subwaveforms in the form (Waveform, List(int)) where the list defines
        the channel mapping, i.e., a value y at index x in the list means that channel x of the
        subwaveform will be mapped to channel y of this MultiChannelWaveform object.

        Args:
            sub_waveforms: The list of sub waveforms of this
                MultiChannelWaveform. List might get sorted!
        Raises:
            ValueError, if a channel mapping is out of bounds of the channels defined by this
                MultiChannelWaveform
            ValueError, if several subwaveform channels are assigned to a single channel of this
                MultiChannelWaveform
            ValueError, if subwaveforms have inconsistent durations
        """

        if not sub_waveforms:
            raise ValueError(
                "MultiChannelWaveform cannot be constructed without channel waveforms."
            )

        # sort the waveforms with their defined channels to make compare key reproducible
        if not isinstance(sub_waveforms, list):
            sub_waveforms = list(sub_waveforms)
        sub_waveforms.sort(key=lambda wf: wf._sort_key_for_channels())

        super().__init__(duration=sub_waveforms[0].duration)
        self._sub_waveforms = tuple(sub_waveforms)

        defined_channels = set()
        for waveform in self._sub_waveforms:
            if waveform.defined_channels & defined_channels:
                raise ValueError(
                    'Channel may not be defined in multiple waveforms',
                    waveform.defined_channels & defined_channels)
            defined_channels |= waveform.defined_channels
        self._defined_channels = frozenset(defined_channels)

        if not all(
                isclose(waveform.duration, self.duration)
                for waveform in self._sub_waveforms[1:]):
            # meaningful error message:
            durations = {}

            for waveform in self._sub_waveforms:
                for duration, channels in durations.items():
                    if isclose(waveform.duration, duration):
                        channels.update(waveform.defined_channels)
                        break
                else:
                    durations[waveform.duration] = set(
                        waveform.defined_channels)

            raise ValueError(
                "MultiChannelWaveform cannot be constructed from channel waveforms of different durations.",
                durations)
    def build_waveform(
        self, parameters: Dict[str, numbers.Real],
        channel_mapping: Dict[ChannelID, Optional[ChannelID]]
    ) -> Optional[Waveform]:
        self.validate_parameter_constraints(parameters=parameters)

        sub_waveforms = []
        for subtemplate in self.subtemplates:
            sub_waveform = subtemplate.build_waveform(
                parameters, channel_mapping=channel_mapping)
            if sub_waveform is not None:
                sub_waveforms.append(sub_waveform)

        if len(sub_waveforms) == 0:
            return None

        if len(sub_waveforms) == 1:
            waveform = sub_waveforms[0]
        else:
            waveform = MultiChannelWaveform(sub_waveforms)

        if self._duration:
            expected_duration = self._duration.evaluate_numeric(**parameters)

            if not isclose(expected_duration, waveform.duration):
                raise ValueError(
                    'The duration does not '
                    'equal the expected duration', expected_duration,
                    waveform.duration)

        return waveform
Пример #3
0
    def test_issue_584_uninitialized_table_sample(self):
        """issue 584"""
        d = 598.3333333333334 - 480
        tpt = TablePulseTemplate(
            entries={'P': [(0, 1.0, 'hold'), (d, 1.0, 'hold')]})
        with mock.patch('qupulse._program.waveforms.PULSE_TO_WAVEFORM_ERROR',
                        1e-6):
            wf = to_waveform(tpt.create_program())
            self.assertTrue(isclose(d, wf.duration, abs_tol=1e-6))

            start_time = 0.
            end_time = wf.duration
            sample_rate = 3.

            sample_count = (end_time - start_time) * sample_rate + 1

            times = np.linspace(float(start_time),
                                float(wf.duration),
                                num=int(sample_count),
                                dtype=float)
            times[-1] = np.nextafter(times[-1], times[-2])

            out = np.full_like(times, fill_value=np.nan)
            sampled = wf.get_sampled(channel='P',
                                     sample_times=times,
                                     output_array=out)

            expected = np.full_like(times, fill_value=1.)
            np.testing.assert_array_equal(expected, sampled)
Пример #4
0
    def from_operator(cls, lhs: Waveform, arithmetic_operator: str,
                      rhs: Waveform):
        # one could optimize rhs_cv to being only created if lhs_cv is not None but this makes the code harder to read
        lhs_cv = lhs.constant_value_dict()
        rhs_cv = rhs.constant_value_dict()
        if lhs_cv is None or rhs_cv is None:
            return cls(lhs, arithmetic_operator, rhs)

        else:
            constant_values = dict(lhs_cv)
            op = cls.operator_map[arithmetic_operator]
            rhs_op = cls.rhs_only_map[arithmetic_operator]

            for ch, rhs_val in rhs_cv.items():
                if ch in constant_values:
                    constant_values[ch] = op(constant_values[ch], rhs_val)
                else:
                    constant_values[ch] = rhs_op(rhs_val)

            duration = lhs.duration
            assert isclose(duration, rhs.duration)

            return ConstantWaveform.from_mapping(duration, constant_values)
Пример #5
0
    def __init__(self, sub_waveforms: Iterable[Waveform]) -> None:
        """Create a new MultiChannelWaveform instance.

        Requires a list of subwaveforms in the form (Waveform, List(int)) where the list defines
        the channel mapping, i.e., a value y at index x in the list means that channel x of the
        subwaveform will be mapped to channel y of this MultiChannelWaveform object.

        Args:
            sub_waveforms (Iterable( Waveform )): The list of sub waveforms of this
                MultiChannelWaveform
        Raises:
            ValueError, if a channel mapping is out of bounds of the channels defined by this
                MultiChannelWaveform
            ValueError, if several subwaveform channels are assigned to a single channel of this
                MultiChannelWaveform
            ValueError, if subwaveforms have inconsistent durations
        """
        super().__init__()
        if not sub_waveforms:
            raise ValueError(
                "MultiChannelWaveform cannot be constructed without channel waveforms."
            )

        # avoid unnecessary multi channel nesting
        def flatten_sub_waveforms(to_flatten):
            for sub_waveform in to_flatten:
                if isinstance(sub_waveform, MultiChannelWaveform):
                    yield from sub_waveform._sub_waveforms
                else:
                    yield sub_waveform

        # sort the waveforms with their defined channels to make compare key reproducible
        def get_sub_waveform_sort_key(waveform):
            return tuple(
                sorted(
                    tuple('{}_stringified_numeric_channel'.
                          format(ch) if isinstance(ch, int) else ch
                          for ch in waveform.defined_channels)))

        self._sub_waveforms = tuple(
            sorted(flatten_sub_waveforms(sub_waveforms),
                   key=get_sub_waveform_sort_key))

        self.__defined_channels = set()
        for waveform in self._sub_waveforms:
            if waveform.defined_channels & self.__defined_channels:
                raise ValueError(
                    'Channel may not be defined in multiple waveforms',
                    waveform.defined_channels & self.__defined_channels)
            self.__defined_channels |= waveform.defined_channels

        if not all(
                isclose(waveform.duration, self._sub_waveforms[0].duration)
                for waveform in self._sub_waveforms[1:]):
            # meaningful error message:
            durations = {}

            for waveform in self._sub_waveforms:
                for duration, channels in durations.items():
                    if isclose(waveform.duration, duration):
                        channels.update(waveform.defined_channels)
                        break
                else:
                    durations[waveform.duration] = set(
                        waveform.defined_channels)

            raise ValueError(
                "MultiChannelWaveform cannot be constructed from channel waveforms of different durations.",
                durations)