Ejemplo n.º 1
0
def _fill_waveform_color(channel: pulse.channels.Channel) \
        -> types.ComplexColors:
    r"""A helper function that returns color code of the fill waveform.

    Args:
        channel: Pulse channel object associated with the fill waveform.

    Raises:
        VisualizationError: When invalid channel is specified.

    Returns:
        A color code of real and imaginary part of the waveform.
    """
    if isinstance(channel, pulse.DriveChannel):
        colors = PULSE_STYLE['formatter.color.fill_waveform_d']
        if isinstance(colors, (tuple, list)):
            colors = types.ComplexColors(*colors)
        return colors
    if isinstance(channel, pulse.ControlChannel):
        colors = PULSE_STYLE['formatter.color.fill_waveform_u']
        if isinstance(colors, (tuple, list)):
            colors = types.ComplexColors(*colors)
        return colors
    if isinstance(channel, pulse.MeasureChannel):
        colors = PULSE_STYLE['formatter.color.fill_waveform_m']
        if isinstance(colors, (tuple, list)):
            colors = types.ComplexColors(*colors)
        return colors
    if isinstance(channel, pulse.AcquireChannel):
        colors = PULSE_STYLE['formatter.color.fill_waveform_a']
        if isinstance(colors, (tuple, list)):
            colors = types.ComplexColors(*colors)
        return colors

    raise VisualizationError('Channel type %s is not supported.' % type(channel))
Ejemplo n.º 2
0
def qreg_creg_ascending(bits: List[types.Bits]) -> List[types.Bits]:
    """Sort bits by ascending order.

    Bit order becomes Q0, Q1, ..., Cl0, Cl1, ...

    Args:
        bits: List of bits to sort.

    Returns:
        Sorted bits.
    """
    qregs = []
    cregs = []

    for bit in bits:
        if isinstance(bit, circuit.Qubit):
            qregs.append(bit)
        elif isinstance(bit, circuit.Clbit):
            cregs.append(bit)
        else:
            VisualizationError(f"Unknown bit {bit} is provided.")

    with warnings.catch_warnings():
        warnings.simplefilter("ignore")
        qregs = sorted(qregs, key=lambda x: x.index, reverse=False)
        cregs = sorted(cregs, key=lambda x: x.index, reverse=False)

    return qregs + cregs
Ejemplo n.º 3
0
def pulse_drawer(data, dt=1, style=None, filename=None,
                 interp_method=None, scaling=None, channels_to_plot=None,
                 plot_all=False, plot_range=None, interactive=False,
                 table=True, label=False, framechange=True,
                 channels=None):
    """Plot the interpolated envelope of pulse

    Args:
        data (ScheduleComponent or SamplePulse): Data to plot
        dt (float): Time interval of samples
        style (PulseStyle or SchedStyle): A style sheet to configure
            plot appearance
        filename (str): Name required to save pulse image
        interp_method (Callable): interpolation function
            See `qiskit.visualization.interpolation` for more information
        scaling (float): scaling of waveform amplitude
        channels_to_plot (list): Deprecated, see `channels`
        plot_all (bool): Plot empty channels
        plot_range (tuple): A tuple of time range to plot
        interactive (bool): When set true show the circuit in a new window
            (this depends on the matplotlib backend being used supporting this)
        table (bool): Draw event table for supported commands
        label (bool): Label individual instructions
        framechange (bool): Add framechange indicators
        channels (list): A list of channel names to plot

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

    Raises:
        VisualizationError: when invalid data is given or lack of information
        ImportError: when matplotlib is not installed
    """
    if channels_to_plot:
        warnings.warn('The parameter "channels_to_plot" is being replaced by "channels"',
                      DeprecationWarning, 3)
        channels = channels_to_plot

    if not _matplotlib.HAS_MATPLOTLIB:
        raise ImportError('Must have Matplotlib installed.')
    if isinstance(data, SamplePulse):
        drawer = _matplotlib.SamplePulseDrawer(style=style)
        image = drawer.draw(data, dt=dt, interp_method=interp_method, scaling=scaling)
    elif isinstance(data, (Schedule, Instruction)):
        drawer = _matplotlib.ScheduleDrawer(style=style)
        image = drawer.draw(data, dt=dt, interp_method=interp_method, scaling=scaling,
                            plot_range=plot_range, plot_all=plot_all, table=table,
                            label=label, framechange=framechange, channels=channels)
    else:
        raise VisualizationError('This data cannot be visualized.')

    if filename:
        image.savefig(filename, dpi=drawer.style.dpi, bbox_inches='tight')

    if get_backend() in ['module://ipykernel.pylab.backend_inline',
                         'nbAgg']:
        _matplotlib.plt.close(image)
    if image and interactive:
        image.show()
    return image
Ejemplo n.º 4
0
    def set_time_range(self,
                       t_start: Union[int, float],
                       t_end: Union[int, float],
                       seconds: bool = True):
        """Set time range to draw.

        All child chart instances are updated when time range is updated.

        Args:
            t_start: Left boundary of drawing in units of cycle time or real time.
            t_end: Right boundary of drawing in units of cycle time or real time.
            seconds: Set `True` if times are given in SI unit rather than dt.

        Raises:
            VisualizationError: When times are given in float without specifying dt.
        """
        # convert into nearest cycle time
        if seconds:
            if self.device.dt is not None:
                t_start = int(np.round(t_start / self.device.dt))
                t_end = int(np.round(t_end / self.device.dt))
            else:
                raise VisualizationError(
                    'Setting time range with SI units requires '
                    'backend `dt` information.')
        self.time_range = (t_start, t_end)
Ejemplo n.º 5
0
def _bloch_multivector_data(state):
    """Return list of Bloch vectors for each qubit

    Args:
        state (DensityMatrix or Statevector): an N-qubit state.

    Returns:
        list: list of Bloch vectors (x, y, z) for each qubit.

    Raises:
        VisualizationError: if input is not an N-qubit state.
    """
    rho = DensityMatrix(state)
    num = rho.num_qubits
    if num is None:
        raise VisualizationError("Input is not a multi-qubit quantum state.")
    pauli_singles = PauliList(["X", "Y", "Z"])
    bloch_data = []
    for i in range(num):
        if num > 1:
            paulis = PauliList.from_symplectic(
                np.zeros((3, (num - 1)), dtype=bool),
                np.zeros((3, (num - 1)), dtype=bool)).insert(i,
                                                             pauli_singles,
                                                             qubit=True)
        else:
            paulis = pauli_singles
        bloch_state = [
            np.real(np.trace(np.dot(mat, rho.data)))
            for mat in paulis.matrix_iter()
        ]
        bloch_data.append(bloch_state)
    return bloch_data
Ejemplo n.º 6
0
def _fill_waveform_color(channel: pulse.channels.Channel) -> str:
    """A helper function that returns the formatter key of the color code.

    Args:
        channel: Pulse channel object associated with the fill waveform.

    Raises:
        VisualizationError: When invalid channel is specified.

    Returns:
        A color code of real and imaginary part of the waveform.
    """
    if isinstance(channel, pulse.DriveChannel):
        return 'color.fill_waveform_d'

    if isinstance(channel, pulse.ControlChannel):
        return 'color.fill_waveform_u'

    if isinstance(channel, pulse.MeasureChannel):
        return 'color.fill_waveform_m'

    if isinstance(channel, pulse.AcquireChannel):
        return 'color.fill_waveform_a'

    if isinstance(channel, types.WaveformChannel):
        return 'color.fill_waveform_w'

    raise VisualizationError('Channel type %s is not supported.' % type(channel))
Ejemplo n.º 7
0
def _freq_to_text(freq: float, unit: str = 'MHz') -> Tuple[str, str]:
    """A helper function to convert a freq value to text with supplementary unit.

    Args:
        freq: A frequency value in units of Hz.
        unit: Supplementary unit. THz, GHz, MHz, kHz, Hz are supported.

    Returns:
        Standard text and latex text of phase value.

    Raises:
        VisualizationError: When unsupported unit is specified.
    """
    unit_table = {'THz': 1e12, 'GHz': 1e9, 'MHz': 1e6, 'kHz': 1e3, 'Hz': 1}

    try:
        value = freq / unit_table[unit]
    except KeyError:
        raise VisualizationError(
            'Unit {unit} is not supported.'.format(unit=unit))

    latex = r'{val:.2f}~{{\rm {unit}}}'.format(val=value, unit=unit)
    plain = '{val:.2f} {unit}'.format(val=value, unit=unit)

    return plain, latex
Ejemplo n.º 8
0
    def __init__(self,
                 data_type: Union[str, Enum],
                 xvals: Union[np.ndarray, List[types.Coordinate]],
                 yvals: Union[np.ndarray, List[types.Coordinate]],
                 channels: Optional[Union[Channel, List[Channel]]] = None,
                 meta: Dict[str, Any] = None,
                 ignore_scaling: bool = False,
                 styles: Dict[str, Any] = None):
        """Create new box.

        Args:
            data_type: String representation of this drawing.
            xvals: Left and right coordinate that the object is drawn.
            yvals: Top and bottom coordinate that the object is drawn.
            channels: Pulse channel object bound to this drawing.
            meta: Meta data dictionary of the object.
            ignore_scaling: Set ``True`` to disable scaling.
            styles: Style keyword args of the object. This conforms to `matplotlib`.

        Raises:
            VisualizationError: When number of data points are not equals to 2.
        """
        if len(xvals) != 2 or len(yvals) != 2:
            raise VisualizationError(
                'Length of data points are not equals to 2.')

        super().__init__(data_type=data_type,
                         xvals=xvals,
                         yvals=yvals,
                         channels=channels,
                         meta=meta,
                         ignore_scaling=ignore_scaling,
                         styles=styles)
Ejemplo n.º 9
0
def _freq_to_text(formatter: Dict[str, Any],
                  freq: float,
                  unit: str = "MHz") -> Tuple[str, str]:
    """A helper function to convert a freq value to text with supplementary unit.

    Args:
        formatter: Dictionary of stylesheet settings.
        freq: A frequency value in units of Hz.
        unit: Supplementary unit. THz, GHz, MHz, kHz, Hz are supported.

    Returns:
        Standard text and latex text of phase value.

    Raises:
        VisualizationError: When unsupported unit is specified.
    """
    try:
        freq = float(freq)
    except TypeError:
        # unbound parameter
        return formatter["unicode_symbol.freq_parameter"], formatter[
            "latex_symbol.freq_parameter"]

    unit_table = {"THz": 1e12, "GHz": 1e9, "MHz": 1e6, "kHz": 1e3, "Hz": 1}

    try:
        value = freq / unit_table[unit]
    except KeyError as ex:
        raise VisualizationError(f"Unit {unit} is not supported.") from ex

    latex = rf"{value:.2f}~{{\rm {unit}}}"
    plain = f"{value:.2f} {unit}"

    return plain, latex
Ejemplo n.º 10
0
def iplot_state(quantum_state, method='city', figsize=None):
    """Plot the quantum state.

    Args:
        quantum_state (ndarray): statevector or density matrix
                                 representation of a quantum state.
        method (str): Plotting method to use.
        figsize (tuple): Figure size in pixels.

    Raises:
        VisualizationError: if the input is not a statevector or density
        matrix, or if the state is not an multi-qubit quantum state.
    """
    warnings.warn(
        "iplot_state is deprecated, and will be removed in \
                  the 0.9 release. Use the iplot_state_ * functions \
                  instead.", DeprecationWarning)
    rho = _validate_input_state(quantum_state)
    if method == "city":
        iplot_state_city(rho, figsize=figsize)
    elif method == "paulivec":
        iplot_state_paulivec(rho, figsize=figsize)
    elif method == "qsphere":
        iplot_state_qsphere(rho, figsize=figsize)
    elif method == "bloch":
        iplot_bloch_multivector(rho, figsize=figsize)
    elif method == "hinton":
        iplot_state_hinton(rho, figsize=figsize)
    else:
        raise VisualizationError('Invalid plot state method.')
Ejemplo n.º 11
0
def qreg_creg_descending(bits: List[types.Bits]) -> List[types.Bits]:
    """Sort bits by descending order.

    Bit order becomes Q_N, Q_N-1, ..., Cl_N, Cl_N-1, ...

    Args:
        bits: List of bits to sort.

    Returns:
        Sorted bits.
    """
    qregs = []
    cregs = []

    for bit in bits:
        if isinstance(bit, circuit.Qubit):
            qregs.append(bit)
        elif isinstance(bit, circuit.Clbit):
            cregs.append(bit)
        else:
            VisualizationError(
                'Unknown bit {bit} is provided.'.format(bit=bit))

    qregs = sorted(qregs, key=lambda x: x.index, reverse=True)
    cregs = sorted(cregs, key=lambda x: x.index, reverse=True)

    return qregs + cregs
Ejemplo n.º 12
0
def _freq_to_text(formatter: Dict[str, Any],
                  freq: float,
                  unit: str = 'MHz') -> Tuple[str, str]:
    """A helper function to convert a freq value to text with supplementary unit.

    Args:
        formatter: Dictionary of stylesheet settings.
        freq: A frequency value in units of Hz.
        unit: Supplementary unit. THz, GHz, MHz, kHz, Hz are supported.

    Returns:
        Standard text and latex text of phase value.

    Raises:
        VisualizationError: When unsupported unit is specified.
    """
    try:
        freq = float(freq)
    except TypeError:
        # unbound parameter
        return formatter['unicode_symbol.freq_parameter'], \
               formatter['latex_symbol.freq_parameter']

    unit_table = {'THz': 1e12, 'GHz': 1e9, 'MHz': 1e6, 'kHz': 1e3, 'Hz': 1}

    try:
        value = freq / unit_table[unit]
    except KeyError:
        raise VisualizationError(
            'Unit {unit} is not supported.'.format(unit=unit))

    latex = r'{val:.2f}~{{\rm {unit}}}'.format(val=value, unit=unit)
    plain = '{val:.2f} {unit}'.format(val=value, unit=unit)

    return plain, latex
Ejemplo n.º 13
0
    def load_program(self,
                     program: Union[pulse.Waveform, pulse.ParametricPulse,
                                    pulse.Schedule]):
        """Load a program to draw.

        Args:
            program: `Waveform`, `ParametricPulse`, or `Schedule` to draw.

        Raises:
            VisualizationError: When input program is invalid data format.
        """
        if isinstance(program, pulse.Schedule):
            self._schedule_loader(program)
        elif isinstance(program, (pulse.Waveform, pulse.ParametricPulse)):
            self._waveform_loader(program)
        else:
            raise VisualizationError('Data type %s is not supported.' %
                                     type(program))

        # update time range
        self.set_time_range(0, program.duration, seconds=False)

        # set title
        self.fig_title = self.layout['figure_title'](program=program,
                                                     device=self.device)
Ejemplo n.º 14
0
    def __init__(self,
                 data_type: Union[str, Enum],
                 xvals: Union[np.ndarray, List[types.Coordinate]],
                 yvals: Union[np.ndarray, List[types.Coordinate]],
                 bit: types.Bits,
                 meta: Dict[str, Any] = None,
                 styles: Dict[str, Any] = None):
        """Create new box.

        Args:
            data_type: String representation of this drawing.
            xvals: Left and right coordinate that the object is drawn.
            yvals: Top and bottom coordinate that the object is drawn.
            bit: Bit associated to this object.
            meta: Meta data dictionary of the object.
            styles: Style keyword args of the object. This conforms to `matplotlib`.

        Raises:
            VisualizationError: When number of data points are not equals to 2.
        """
        if len(xvals) != 2 or len(yvals) != 2:
            raise VisualizationError(
                'Length of data points are not equals to 2.')

        super().__init__(data_type=data_type,
                         xvals=xvals,
                         yvals=yvals,
                         bits=bit,
                         meta=meta,
                         styles=styles)
Ejemplo n.º 15
0
    def draw(self):
        """Output drawings stored in canvas object."""

        for _, data in self.canvas.collections:
            xvals = np.asarray(data.xvals, dtype=float)
            yvals = np.asarray(data.yvals, dtype=float)
            offsets = [
                self.canvas.assigned_coordinates[bit] for bit in data.bits
            ]

            if isinstance(data, drawings.BoxData):
                # box data
                if data.data_type in [
                        str(types.BoxType.SCHED_GATE.value),
                        str(types.BoxType.DELAY.value),
                ]:
                    # draw a smoothly rounded rectangle
                    xs, ys1, ys2 = self._time_bucket_outline(xvals, yvals)
                    self.ax.fill_between(x=xs,
                                         y1=ys1 + offsets[0],
                                         y2=ys2 + offsets[0],
                                         **data.styles)

                else:
                    # draw a rectangle
                    x0, x1 = xvals
                    y0, y1 = yvals + offsets[0]

                    rect = Rectangle(xy=(x0, y0),
                                     width=x1 - x0,
                                     height=y1 - y0)
                    pc = PatchCollection([rect], **data.styles)
                    self.ax.add_collection(pc)

            elif isinstance(data, drawings.LineData):
                # line data
                self.ax.plot(xvals, yvals + offsets[0], **data.styles)

            elif isinstance(data, drawings.TextData):
                # text data
                if data.latex is not None:
                    s = rf"${data.latex}$"
                else:
                    s = data.text

                self.ax.text(x=xvals[0],
                             y=yvals[0] + offsets[0],
                             s=s,
                             **data.styles)

            elif isinstance(data, drawings.GateLinkData):
                # gate link data
                self.ax.plot(xvals.repeat(len(offsets)), offsets,
                             **data.styles)

            else:
                VisualizationError("Data {name} is not supported by {plotter}"
                                   "".format(name=data,
                                             plotter=self.__class__.__name__))
Ejemplo n.º 16
0
def bit_string_index(s):
    """Return the index of a string of 0s and 1s."""
    n = len(s)
    k = s.count("1")
    if s.count("0") != n - k:
        raise VisualizationError("s must be a string of 0 and 1")
    ones = [pos for pos, char in enumerate(s) if char == "1"]
    return lex_index(n, k, ones)
Ejemplo n.º 17
0
def _parse_waveform(data: types.PulseInstruction) -> types.ParsedInstruction:
    """A helper function that generates an array for the waveform with
    instruction metadata.

    Args:
        data: Instruction data set

    Raises:
        VisualizationError: When invalid instruction type is loaded.

    Returns:
        A data source to generate a drawing object.
    """
    inst = data.inst

    meta = dict()
    if isinstance(inst, instructions.Play):
        # pulse
        operand = inst.pulse
        if isinstance(operand, pulse.ParametricPulse):
            pulse_data = operand.get_waveform()
            meta.update(operand.parameters)
        else:
            pulse_data = operand
        xdata = np.arange(pulse_data.duration) + data.t0
        ydata = pulse_data.samples
    elif isinstance(inst, instructions.Delay):
        # delay
        xdata = np.arange(inst.duration) + data.t0
        ydata = np.zeros(inst.duration)
    elif isinstance(inst, instructions.Acquire):
        # acquire
        xdata = np.arange(inst.duration) + data.t0
        ydata = np.ones(inst.duration)
        acq_data = {
            'memory slot': inst.mem_slot.name,
            'register slot': inst.reg_slot.name if inst.reg_slot else 'N/A',
            'discriminator':
            inst.discriminator.name if inst.discriminator else 'N/A',
            'kernel': inst.kernel.name if inst.kernel else 'N/A'
        }
        meta.update(acq_data)
    else:
        raise VisualizationError(
            'Unsupported instruction {inst} by '
            'filled envelope.'.format(inst=inst.__class__.__name__))

    meta.update({
        'duration (cycle time)': inst.duration,
        'duration (sec)': inst.duration * data.dt if data.dt else 'N/A',
        't0 (cycle time)': data.t0,
        't0 (sec)': data.t0 * data.dt if data.dt else 'N/A',
        'phase': data.frame.phase,
        'frequency': data.frame.freq,
        'name': inst.name
    })

    return types.ParsedInstruction(xdata, ydata, meta)
Ejemplo n.º 18
0
 def substitute(val: types.Coordinate):
     if val == types.AbstractCoordinate.LEFT:
         return self.parent.time_range[0]
     if val == types.AbstractCoordinate.RIGHT:
         return self.parent.time_range[1]
     if val == types.AbstractCoordinate.TOP:
         return self.vmax
     if val == types.AbstractCoordinate.BOTTOM:
         return self.vmin
     raise VisualizationError('Coordinate {name} is not supported.'.format(name=val))
Ejemplo n.º 19
0
 def substitute(val: types.Coordinate):
     if val == types.AbstractCoordinate.LEFT:
         return self.time_range[0]
     if val == types.AbstractCoordinate.RIGHT:
         return self.time_range[1]
     if val == types.AbstractCoordinate.TOP:
         return self.vmax
     if val == types.AbstractCoordinate.BOTTOM:
         return self.vmin
     raise VisualizationError(f"Coordinate {val} is not supported.")
Ejemplo n.º 20
0
def _validate_input_state(quantum_state):
    """Validates the input to state visualization functions.

    Args:
        quantum_state (ndarray): Input state / density matrix.
    Returns:
        rho: A 2d numpy array for the density matrix.
    Raises:
        VisualizationError: Invalid input.
    """
    rho = np.asarray(quantum_state)
    if rho.ndim == 1:
        rho = np.outer(rho, np.conj(rho))
    # Check the shape of the input is a square matrix
    shape = np.shape(rho)
    if len(shape) != 2 or shape[0] != shape[1]:
        raise VisualizationError("Input is not a valid quantum state.")
    # Check state is an n-qubit state
    num = int(np.log2(rho.shape[0]))
    if 2 ** num != rho.shape[0]:
        raise VisualizationError("Input is not a multi-qubit quantum state.")
    return rho
Ejemplo n.º 21
0
def _parse_waveform(inst_data: types.InstructionTuple) \
        -> Tuple[np.ndarray, np.ndarray, Dict[str, Any]]:
    r"""A helper function that generates sample data array of the waveform with
    instruction meta data.

    Args:
        inst_data: Instruction data set

    Raises:
        VisualizationError: When invalid instruction type is loaded.

    Returns:
        A tuple of xy data and metadata dictionary.
    """
    inst = inst_data.inst

    meta = dict()
    if isinstance(inst, instructions.Play):
        # pulse
        if isinstance(inst.pulse, pulse.ParametricPulse):
            pulse_data = inst.pulse.get_sample_pulse()
            meta.update(inst.pulse.parameters)
        else:
            pulse_data = inst.pulse
        xdata = np.arange(pulse_data.duration) + inst_data.t0
        ydata = pulse_data.samples
    elif isinstance(inst, instructions.Delay):
        # delay
        xdata = np.arange(inst.duration) + inst_data.t0
        ydata = np.zeros(inst.duration)
    elif isinstance(inst, instructions.Acquire):
        # acquire
        xdata = np.arange(inst.duration) + inst_data.t0
        ydata = np.ones(inst.duration)
        acq_data = {'memory slot': inst.mem_slot.name,
                    'register slot': inst.reg_slot.name if inst.reg_slot else 'N/A',
                    'discriminator': inst.discriminator.name if inst.discriminator else 'N/A',
                    'kernel': inst.kernel.name if inst.kernel else 'N/A'}
        meta.update(acq_data)
    else:
        raise VisualizationError('Instruction %s cannot be drawn by filled envelope.' % type(inst))

    meta.update({'duration (cycle time)': inst.duration,
                 'duration (sec)': inst.duration * inst_data.dt if inst_data.dt else 'N/A',
                 't0 (cycle time)': inst_data.t0,
                 't0 (sec)': inst_data.t0 * inst_data.dt if inst_data.dt else 'N/A',
                 'phase': inst_data.frame.phase,
                 'frequency': inst_data.frame.freq,
                 'name': inst.name})

    return xdata, ydata, meta
Ejemplo n.º 22
0
def _paulivec_data(state):
    """Return paulivec data for plotting.

    Args:
        state (DensityMatrix or Statevector): an N-qubit state.

    Returns:
        tuple: (labels, values) for Pauli vector.

    Raises:
        VisualizationError: if input is not an N-qubit state.
    """
    rho = SparsePauliOp.from_operator(DensityMatrix(state))
    if rho.num_qubits is None:
        raise VisualizationError("Input is not a multi-qubit quantum state.")
    return rho.paulis.to_labels(), np.real(rho.coeffs)
Ejemplo n.º 23
0
def lex_index(n, k, lst):
    """Return  the lex index of a combination..

    Args:
        n (int): the total number of options .
        k (int): The number of elements.
        lst (list): list

    Returns:
        int: returns int index for lex order

    Raises:
        VisualizationError: if length of list is not equal to k
    """
    if len(lst) != k:
        raise VisualizationError("list should have length k")
    comb = list(map(lambda x: n - 1 - x, lst))
    dualm = sum(n_choose_k(comb[k - 1 - i], i + 1) for i in range(k))
    return int(dualm)
Ejemplo n.º 24
0
    def __init__(self,
                 data_type: str,
                 channel: channels.Channel,
                 x: Optional[Union[np.ndarray, float]],
                 y: Optional[Union[np.ndarray, float]],
                 meta: Optional[Dict[str, Any]] = None,
                 offset: float = 0,
                 scale: float = 1,
                 visible: bool = True,
                 styles: Optional[Dict[str, Any]] = None):
        """Create new drawing object of line data.

        Args:
            data_type: String representation of this drawing object.
            channel: Pulse channel object bound to this drawing.
            x: Series of horizontal coordinate that the object is drawn.
                If `x` is `None`, a horizontal line is drawn at `y`.
            y: Series of vertical coordinate that the object is drawn.
                If `y` is `None`, a vertical line is drawn at `x`.
            meta: Meta data dictionary of the object.
            offset: Offset coordinate of vertical axis.
            scale: Vertical scaling factor of this object.
            visible: Set ``True`` to show the component on the canvas.
            styles: Style keyword args of the object. This conforms to `matplotlib`.

        Raises:
            VisualizationError: When both `x` and `y` are None.
        """
        if x is None and y is None:
            raise VisualizationError('`x` and `y` cannot be None simultaneously.')

        self.x = x
        self.y = y

        super().__init__(data_type=data_type,
                         channel=channel,
                         meta=meta,
                         offset=offset,
                         scale=scale,
                         visible=visible,
                         styles=styles)
Ejemplo n.º 25
0
    def load_program(cls, scheduled_circuit: circuit.QuantumCircuit,
                     bit: types.Bits):
        """Build new BitEvents from scheduled circuit.

        Args:
            scheduled_circuit: Scheduled circuit object to draw.
            bit: Target bit object.

        Returns:
            BitEvents: New `BitEvents` object.

        Raises:
            VisualizationError: When the circuit is not transpiled with duration.
        """
        t0 = 0
        tf = scheduled_circuit.qubit_stop_time(bit)

        instructions = []
        for inst, qargs, cargs in scheduled_circuit.data:
            associated_bits = qargs + cargs
            if bit not in associated_bits:
                continue

            duration = inst.duration
            if duration is None:
                raise VisualizationError(
                    "Instruction {oper} has no duration. "
                    "You need to transpile the QuantumCircuit with "
                    "gate durations before drawing.".format(oper=inst))

            instructions.append(
                types.ScheduledGate(
                    t0=t0,
                    operand=inst,
                    duration=duration,
                    bits=associated_bits,
                    bit_position=associated_bits.index(bit),
                ))
            t0 += duration

        return BitEvents(bit, instructions, tf)
Ejemplo n.º 26
0
    def load_program(cls,
                     scheduled_circuit: circuit.QuantumCircuit,
                     bit: types.Bits):
        """Build new BitEvents from scheduled circuit.

        Args:
            scheduled_circuit: Scheduled circuit object to draw.
            bit: Target bit object.

        Returns:
            BitEvents: New `BitEvents` object.

        Raises:
            VisualizationError: When the circuit is not transpiled with duration.
        """
        dag = circuit_to_dag(scheduled_circuit)
        nodes = list(dag.topological_op_nodes())

        t0 = 0
        instructions = []
        for node in nodes:
            associated_bits = node.qargs + node.cargs
            if bit not in associated_bits:
                continue

            duration = node.op.duration
            if duration is None:
                raise VisualizationError('Instruction {oper} has no duration. '
                                         'You need to transpile the QuantumCircuit with '
                                         'gate durations before drawing.'.format(oper=node.op))

            instructions.append(types.ScheduledGate(t0=t0,
                                                    operand=node.op,
                                                    duration=duration,
                                                    bits=associated_bits,
                                                    bit_position=associated_bits.index(bit)))
            t0 += duration

        return BitEvents(bit, instructions)
Ejemplo n.º 27
0
    def time_breaks(self) -> List[Tuple[int, int]]:
        """Return time breaks with time range.

        If an edge of time range is in the axis break period,
        the axis break period is recalculated.

        Raises:
            VisualizationError: When axis break is greater than time window.

        Returns:
            List of axis break periods considering the time window edges.
        """
        t0, t1 = self._time_range

        axis_breaks = []
        for t0b, t1b in self._time_breaks:
            if t0b >= t1 or t1b <= t0:
                # skip because break period is outside of time window
                continue

            if t0b < t0 and t1b > t1:
                raise VisualizationError(
                    'Axis break is greater than time window. '
                    'Nothing will be drawn.')
            if t0b < t0 < t1b:
                if t1b - t0 > self.formatter['axis_break.length']:
                    new_t0 = t0 + 0.5 * self.formatter['axis_break.max_length']
                    axis_breaks.append((new_t0, t1b))
                continue
            if t0b < t1 < t1b:
                if t1 - t0b > self.formatter['axis_break.length']:
                    new_t1 = t1 - 0.5 * self.formatter['axis_break.max_length']
                    axis_breaks.append((t0b, new_t1))
                continue
            axis_breaks.append((t0b, t1b))

        return axis_breaks
Ejemplo n.º 28
0
def circuit_drawer(
    circuit,
    scale=None,
    filename=None,
    style=None,
    output=None,
    interactive=False,
    plot_barriers=True,
    reverse_bits=False,
    justify=None,
    vertical_compression="medium",
    idle_wires=True,
    with_layout=True,
    fold=None,
    ax=None,
    initial_state=False,
    cregbundle=True,
):
    """Draw the quantum circuit. Use the output parameter to choose the drawing format:

    **text**: ASCII art TextDrawing that can be printed in the console.

    **matplotlib**: images with color rendered purely in Python.

    **latex**: high-quality images compiled via latex.

    **latex_source**: raw uncompiled latex output.

    Args:
        circuit (QuantumCircuit): the quantum circuit to draw
        scale (float): scale of image to draw (shrink if < 1.0). Only used by
            the `mpl`, `latex` and `latex_source` outputs. Defaults to 1.0.
        filename (str): file path to save image to. Defaults to None.
        style (dict or str): dictionary of style or file name of style json file.
            This option is only used by the `mpl` or `latex` output type.
            If `style` is a str, it is used as the path to a json file
            which contains a style dict. The file will be opened, parsed, and
            then any style elements in the dict will replace the default values
            in the input dict. A file to be loaded must end in ``.json``, but
            the name entered here can omit ``.json``. For example,
            ``style='iqx.json'`` or ``style='iqx'``.
            If `style` is a dict and the ``'name'`` key is set, that name
            will be used to load a json file, followed by loading the other
            items in the style dict. For example, ``style={'name': 'iqx'}``.
            If `style` is not a str and `name` is not a key in the style dict,
            then the default value from the user config file (usually
            ``~/.qiskit/settings.conf``) will be used, for example,
            ``circuit_mpl_style = iqx``.
            If none of these are set, the `default` style will be used.
            The search path for style json files can be specified in the user
            config, for example,
            ``circuit_mpl_style_path = /home/user/styles:/home/user``.
            See: :class:`~qiskit.visualization.qcstyle.DefaultStyle` for more
            information on the contents.
        output (str): select the output method to use for drawing the circuit.
            Valid choices are ``text``, ``mpl``, ``latex``, ``latex_source``.
            By default the `text` drawer is used unless the user config file
            (usually ``~/.qiskit/settings.conf``) has an alternative backend set
            as the default. For example, ``circuit_drawer = latex``. If the output
            kwarg is set, that backend will always be used over the default in
            the user config file.
        interactive (bool): when set to true, show the circuit in a new window
            (for `mpl` this depends on the matplotlib backend being used
            supporting this). Note when used with either the `text` or the
            `latex_source` output type this has no effect and will be silently
            ignored. Defaults to False.
        reverse_bits (bool): when set to True, reverse the bit order inside
            registers for the output visualization. Defaults to False.
        plot_barriers (bool): enable/disable drawing barriers in the output
            circuit. Defaults to True.
        justify (string): options are ``left``, ``right`` or ``none``. If
            anything else is supplied, it defaults to left justified. It refers
            to where gates should be placed in the output circuit if there is
            an option. ``none`` results in each gate being placed in its own
            column.
        vertical_compression (string): ``high``, ``medium`` or ``low``. It
            merges the lines generated by the `text` output so the drawing
            will take less vertical room.  Default is ``medium``. Only used by
            the `text` output, will be silently ignored otherwise.
        idle_wires (bool): include idle wires (wires with no circuit elements)
            in output visualization. Default is True.
        with_layout (bool): include layout information, with labels on the
            physical layout. Default is True.
        fold (int): sets pagination. It can be disabled using -1. In `text`,
            sets the length of the lines. This is useful when the drawing does
            not fit in the console. If None (default), it will try to guess the
            console width using ``shutil.get_terminal_size()``. However, if
            running in jupyter, the default line length is set to 80 characters.
            In `mpl`, it is the number of (visual) layers before folding.
            Default is 25.
        ax (matplotlib.axes.Axes): Only used by the `mpl` backend. An optional
            Axes object to be used for the visualization output. If none is
            specified, a new matplotlib Figure will be created and used.
            Additionally, if specified there will be no returned Figure since
            it is redundant.
        initial_state (bool): optional. Adds ``|0>`` in the beginning of the wire.
            Default is False.
        cregbundle (bool): optional. If set True, bundle classical registers.
            Default is True.

    Returns:
        :class:`TextDrawing` or :class:`matplotlib.figure` or :class:`PIL.Image` or
        :class:`str`:

        * `TextDrawing` (output='text')
            A drawing that can be printed as ascii art.
        * `matplotlib.figure.Figure` (output='mpl')
            A matplotlib figure object for the circuit diagram.
        * `PIL.Image` (output='latex')
            An in-memory representation of the image of the circuit diagram.
        * `str` (output='latex_source')
            The LaTeX source code for visualizing the circuit diagram.

    Raises:
        VisualizationError: when an invalid output method is selected
        MissingOptionalLibraryError: when the output methods requires non-installed libraries.

    Example:
        .. jupyter-execute::

            from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit
            from qiskit.tools.visualization import circuit_drawer
            q = QuantumRegister(1)
            c = ClassicalRegister(1)
            qc = QuantumCircuit(q, c)
            qc.h(q)
            qc.measure(q, c)
            circuit_drawer(qc, output='mpl', style={'backgroundcolor': '#EEEEEE'})
    """
    image = None
    config = user_config.get_config()
    # Get default from config file else use text
    default_output = "text"
    if config:
        default_output = config.get("circuit_drawer", "text")
        if default_output == "auto":
            if _matplotlib.HAS_MATPLOTLIB:
                default_output = "mpl"
            else:
                default_output = "text"
    if output is None:
        output = default_output

    if output == "text":
        return _text_circuit_drawer(
            circuit,
            filename=filename,
            reverse_bits=reverse_bits,
            plot_barriers=plot_barriers,
            justify=justify,
            vertical_compression=vertical_compression,
            idle_wires=idle_wires,
            with_layout=with_layout,
            fold=fold,
            initial_state=initial_state,
            cregbundle=cregbundle,
        )
    elif output == "latex":
        image = _latex_circuit_drawer(
            circuit,
            filename=filename,
            scale=scale,
            style=style,
            plot_barriers=plot_barriers,
            reverse_bits=reverse_bits,
            justify=justify,
            idle_wires=idle_wires,
            with_layout=with_layout,
            initial_state=initial_state,
            cregbundle=cregbundle,
        )
    elif output == "latex_source":
        return _generate_latex_source(
            circuit,
            filename=filename,
            scale=scale,
            style=style,
            plot_barriers=plot_barriers,
            reverse_bits=reverse_bits,
            justify=justify,
            idle_wires=idle_wires,
            with_layout=with_layout,
            initial_state=initial_state,
            cregbundle=cregbundle,
        )
    elif output == "mpl":
        image = _matplotlib_circuit_drawer(
            circuit,
            scale=scale,
            filename=filename,
            style=style,
            plot_barriers=plot_barriers,
            reverse_bits=reverse_bits,
            justify=justify,
            idle_wires=idle_wires,
            with_layout=with_layout,
            fold=fold,
            ax=ax,
            initial_state=initial_state,
            cregbundle=cregbundle,
        )
    else:
        raise VisualizationError(
            "Invalid output type %s selected. The only valid choices "
            "are text, latex, latex_source, and mpl" % output
        )
    if image and interactive:
        image.show()
    return image
Ejemplo n.º 29
0
def _parse_waveform(
    data: types.PulseInstruction,
) -> Union[types.ParsedInstruction, types.OpaqueShape]:
    """A helper function that generates an array for the waveform with
    instruction metadata.

    Args:
        data: Instruction data set

    Raises:
        VisualizationError: When invalid instruction type is loaded.

    Returns:
        A data source to generate a drawing.
    """
    inst = data.inst

    meta = {}
    if isinstance(inst, instructions.Play):
        # pulse
        operand = inst.pulse
        if isinstance(operand, (pulse.ParametricPulse, pulse.SymbolicPulse)):
            # parametric pulse
            params = operand.parameters
            duration = params.pop("duration", None)
            if isinstance(duration, circuit.Parameter):
                duration = None

            if hasattr(operand, "pulse_type"):
                # Symbolic pulse
                meta["waveform shape"] = operand.pulse_type
            else:
                meta["waveform"] = operand.__class__.__name__

            meta.update({
                key: val.name if isinstance(val, circuit.Parameter) else val
                for key, val in params.items()
            })
            if data.is_opaque:
                # parametric pulse with unbound parameter
                if duration:
                    meta.update({
                        "duration (cycle time)":
                        inst.duration,
                        "duration (sec)":
                        inst.duration * data.dt if data.dt else "N/A",
                    })
                else:
                    meta.update({
                        "duration (cycle time)": "N/A",
                        "duration (sec)": "N/A"
                    })

                meta.update({
                    "t0 (cycle time)": data.t0,
                    "t0 (sec)": data.t0 * data.dt if data.dt else "N/A",
                    "phase": data.frame.phase,
                    "frequency": data.frame.freq,
                    "name": inst.name,
                })

                return types.OpaqueShape(duration=duration, meta=meta)
            else:
                # fixed shape parametric pulse
                pulse_data = operand.get_waveform()
        else:
            # waveform
            pulse_data = operand
        xdata = np.arange(pulse_data.duration) + data.t0
        ydata = pulse_data.samples
    elif isinstance(inst, instructions.Delay):
        # delay
        xdata = np.arange(inst.duration) + data.t0
        ydata = np.zeros(inst.duration)
    elif isinstance(inst, instructions.Acquire):
        # acquire
        xdata = np.arange(inst.duration) + data.t0
        ydata = np.ones(inst.duration)
        acq_data = {
            "memory slot": inst.mem_slot.name,
            "register slot": inst.reg_slot.name if inst.reg_slot else "N/A",
            "discriminator":
            inst.discriminator.name if inst.discriminator else "N/A",
            "kernel": inst.kernel.name if inst.kernel else "N/A",
        }
        meta.update(acq_data)
    else:
        raise VisualizationError(
            "Unsupported instruction {inst} by "
            "filled envelope.".format(inst=inst.__class__.__name__))

    meta.update({
        "duration (cycle time)": inst.duration,
        "duration (sec)": inst.duration * data.dt if data.dt else "N/A",
        "t0 (cycle time)": data.t0,
        "t0 (sec)": data.t0 * data.dt if data.dt else "N/A",
        "phase": data.frame.phase,
        "frequency": data.frame.freq,
        "name": inst.name,
    })

    return types.ParsedInstruction(xvals=xdata, yvals=ydata, meta=meta)
Ejemplo n.º 30
0
def gen_filled_waveform_stepwise(
    data: types.PulseInstruction, formatter: Dict[str, Any],
    device: device_info.DrawerBackendInfo
) -> List[Union[drawings.LineData, drawings.BoxData, drawings.TextData]]:
    """Generate filled area objects of the real and the imaginary part of waveform envelope.

    The curve of envelope is not interpolated nor smoothed and presented
    as stepwise function at each data point.

    Stylesheets:
        - The `fill_waveform` style is applied.

    Args:
        data: Waveform instruction data to draw.
        formatter: Dictionary of stylesheet settings.
        device: Backend configuration.

    Returns:
        List of `LineData`, `BoxData`, or `TextData` drawings.

    Raises:
        VisualizationError: When the instruction parser returns invalid data format.
    """
    # generate waveform data
    waveform_data = _parse_waveform(data)
    channel = data.inst.channel

    # update metadata
    meta = waveform_data.meta
    qind = device.get_qubit_index(channel)
    meta.update({"qubit": qind if qind is not None else "N/A"})

    if isinstance(waveform_data, types.ParsedInstruction):
        # Draw waveform with fixed shape

        xdata = waveform_data.xvals
        ydata = waveform_data.yvals

        # phase modulation
        if formatter["control.apply_phase_modulation"]:
            ydata = np.asarray(ydata, dtype=complex) * np.exp(
                1j * data.frame.phase)
        else:
            ydata = np.asarray(ydata, dtype=complex)

        return _draw_shaped_waveform(xdata=xdata,
                                     ydata=ydata,
                                     meta=meta,
                                     channel=channel,
                                     formatter=formatter)

    elif isinstance(waveform_data, types.OpaqueShape):
        # Draw parametric pulse with unbound parameters

        # parameter name
        unbound_params = []
        for pname, pval in data.inst.pulse.parameters.items():
            if isinstance(pval, circuit.ParameterExpression):
                unbound_params.append(pname)

        if hasattr(data.inst.pulse, "pulse_type"):
            pulse_shape = data.inst.pulse.pulse_type
        else:
            pulse_shape = data.inst.pulse.__class__.__name__

        return _draw_opaque_waveform(
            init_time=data.t0,
            duration=waveform_data.duration,
            pulse_shape=pulse_shape,
            pnames=unbound_params,
            meta=meta,
            channel=channel,
            formatter=formatter,
        )

    else:
        raise VisualizationError("Invalid data format is provided.")