Exemple #1
0
    def _push_left_append(this: Schedule,
                          other: ScheduleComponent) -> Schedule:
        """Return ``this`` with ``other`` inserted at the maximum time over
        all channels shared between ```this`` and ``other``.

        Args:
            this: Input schedule to which ``other`` will be inserted.
            other: Other schedule to insert.

        Returns:
            Push left appended schedule.
        """
        this_channels = set(this.channels)
        other_channels = set(other.channels)
        shared_channels = list(this_channels & other_channels)
        ch_slacks = [
            this.stop_time - this.ch_stop_time(channel) +
            other.ch_start_time(channel) for channel in shared_channels
        ]

        if ch_slacks:
            slack_chan = shared_channels[np.argmin(ch_slacks)]
            shared_insert_time = this.ch_stop_time(
                slack_chan) - other.ch_start_time(slack_chan)
        else:
            shared_insert_time = 0

        # Handle case where channels not common to both might actually start
        # after ``this`` has finished.
        other_only_insert_time = other.ch_start_time(*(other_channels -
                                                       this_channels))
        # Choose whichever is greatest.
        insert_time = max(shared_insert_time, other_only_insert_time)

        return this.insert(insert_time, other, inplace=True)
Exemple #2
0
    def _push_right_prepend(this: ScheduleComponent,
                            other: ScheduleComponent) -> Schedule:
        """Return ``this`` with ``other`` inserted at the latest possible time
        such that ``other`` ends before it overlaps with any of ``this``.

        If required ``this`` is shifted  to start late enough so that there is room
        to insert ``other``.

        Args:
           this: Input schedule to which ``other`` will be inserted.
           other: Other schedule to insert.

        Returns:
           Push right prepended schedule.
        """
        this_channels = set(this.channels)
        other_channels = set(other.channels)
        shared_channels = list(this_channels & other_channels)
        ch_slacks = [
            this.ch_start_time(channel) - other.ch_stop_time(channel)
            for channel in shared_channels
        ]

        if ch_slacks:
            insert_time = min(ch_slacks) + other.start_time
        else:
            insert_time = this.stop_time - other.stop_time + other.start_time

        if insert_time < 0:
            this.shift(-insert_time, inplace=True)
            this.insert(0, other, inplace=True)
        else:
            this.insert(insert_time, other, inplace=True)

        return this
Exemple #3
0
    def draw(
        self,
        schedule: ScheduleComponent,
        dt: float,
        interp_method: Callable,
        plot_range: Tuple[float, float],
        scale: float = None,
        channel_scales: Dict[Channel, float] = None,
        plot_all: bool = True,
        table: bool = False,
        label: bool = False,
        framechange: bool = True,
        channels: List[Channel] = None,
        show_framechange_channels: bool = True,
        draw_title: bool = False,
    ):
        """Draw figure.

        Args:
            schedule: schedule object to plot.
            dt: Time interval of samples. Pulses are visualized in the unit of
                cycle time if not provided.
            interp_method: Interpolation function. See example.
                Interpolation is disabled in default.
                See `qiskit.visualization.pulse.interpolation` for more information.
            plot_range: A tuple of time range to plot.
            scale: Scaling of waveform amplitude. Pulses are automatically
                scaled channel by channel if not provided.
            channel_scales: Dictionary of scale factor for specific channels.
                Scale of channels not specified here is overwritten by `scale`.
            plot_all: When set `True` plot empty channels.
            table: When set `True` draw event table for supported commands.
            label: When set `True` draw label for individual instructions.
            framechange: When set `True` draw framechange indicators.
            channels: A list of channel names to plot.
                All non-empty channels are shown if not provided.
            show_framechange_channels: When set `True` plot channels
                with only framechange instructions.
            draw_title: Add a title to the plot when set to ``True``.

        Returns:
            matplotlib.figure.Figure: A matplotlib figure object for the pulse envelope.

        Raises:
            VisualizationError: When schedule cannot be drawn
        """
        figure = self.plt_mod.figure(dpi=self.style.dpi,
                                     figsize=self.style.figsize)

        if channels is None:
            channels = []
        interp_method = interp_method or step_wise

        if channel_scales is None:
            channel_scales = {}

        # setup plot range
        if plot_range:
            t0 = int(np.floor(plot_range[0]))
            tf = int(np.floor(plot_range[1]))
        else:
            t0 = 0
            # when input schedule is empty or comprises only frame changes,
            # we need to overwrite pulse duration by an integer greater than zero,
            # otherwise waveform returns empty array and matplotlib will be crashed.
            if channels:
                tf = schedule.ch_duration(*channels)
            else:
                tf = schedule.stop_time
            tf = tf or 1

        # prepare waveform channels
        (schedule_channels, output_channels,
         snapshot_channels) = self._build_channels(schedule, channels, t0, tf,
                                                   show_framechange_channels)

        # count numbers of valid waveform
        scale_dict = self._scale_channels(
            output_channels,
            scale=scale,
            channel_scales=channel_scales,
            channels=channels,
            plot_all=plot_all,
        )

        if table:
            tb, ax = self._draw_table(figure, schedule_channels, dt)
        else:
            tb = None
            ax = figure.add_subplot(111)

        ax.set_facecolor(self.style.bg_color)

        y0 = self._draw_channels(
            ax,
            output_channels,
            interp_method,
            t0,
            tf,
            scale_dict,
            label=label,
            framechange=framechange,
        )

        y_ub = 0.5 + self.style.vertical_span
        y_lb = y0 + 0.5 - self.style.vertical_span

        self._draw_snapshots(ax, snapshot_channels, y_lb)

        ax.set_xlim(t0, tf)
        tick_labels = np.linspace(t0, tf, 5)
        ax.set_xticks(tick_labels)
        ax.set_xticklabels(
            [self.style.axis_formatter % label for label in tick_labels * dt],
            fontsize=self.style.axis_font_size,
        )
        ax.set_ylim(y_lb, y_ub)
        ax.set_yticklabels([])

        if tb is not None:
            bbox = tb.get_position()
        else:
            bbox = ax.get_position()

        # This check is here for backwards compatibility. Before, the check was around
        # the suptitle line, however since the font style can take on a type of None
        # we need to unfortunately check both the type and the value of the object.
        if isinstance(self.style.title_font_size,
                      int) and self.style.title_font_size > 0:
            if draw_title:
                figure.suptitle(
                    schedule.name,
                    fontsize=self.style.title_font_size,
                    y=bbox.y1 + 0.02,
                    va="bottom",
                )
        return figure