Esempio n. 1
0
    def _build_measure(self, op, col):
        """Build a meter and the lines to the creg"""
        if op.op.condition:
            raise exceptions.VisualizationError(
                "If controlled measures currently not supported.")

        wire1 = self.img_regs[op.qargs[0]]
        if self.cregbundle:
            wire2 = len(self.qubit_list)
            cregindex = self.img_regs[op.cargs[0]] - wire2
            for creg_size in self.cregs.values():
                if cregindex >= creg_size:
                    cregindex -= creg_size
                    wire2 += 1
                else:
                    break
        else:
            wire2 = self.img_regs[op.cargs[0]]

        self._latex[wire1][col] = "\\meter"
        if self.cregbundle:
            self._latex[wire2][col] = "\\dstick{_{_{%s}}} \\cw \\cwx[-%s]" % (
                str(cregindex),
                str(wire2 - wire1),
            )
        else:
            self._latex[wire2][col] = "\\control \\cw \\cwx[-" + str(
                wire2 - wire1) + "]"
Esempio n. 2
0
 def _get_qubit_index(self, qubit):
     """Get the index number for a quantum bit
     Args:
         qubit (tuple): The tuple of the bit of the form
             (register_name, bit_number)
     Returns:
         int: The index in the bit list
     Raises:
         VisualizationError: If the bit isn't found
     """
     for i, bit in enumerate(self.qubit_list):
         if qubit == bit:
             qindex = i
             break
     else:
         raise exceptions.VisualizationError("unable to find bit for operation")
     return qindex
def circuit_drawer(circuit,
                   scale=0.7,
                   filename=None,
                   style=None,
                   output=None,
                   interactive=False,
                   line_length=None,
                   plot_barriers=True,
                   reverse_bits=False,
                   justify=None,
                   vertical_compression='medium',
                   idle_wires=True,
                   with_layout=True,
                   fold=None,
                   ax=None):
    """Draw a quantum circuit to different formats (set by output parameter):
    0. text: ASCII art TextDrawing that can be printed in the console.
    1. latex: high-quality images, but heavy external software dependencies
    2. matplotlib: purely in Python with no external dependencies

    Args:
        circuit (QuantumCircuit): the quantum circuit to draw
        scale (float): scale of image to draw (shrink if < 1)
        filename (str): file path to save image to
        style (dict or str): dictionary of style or file name of style file.
            This option is only used by the `mpl`, `latex`, and `latex_source`
            output types. If a str is passed in that is the path to a json
            file which contains that will be open, parsed, and then used just
            as the input dict.
        output (str): Select the output method to use for drawing the circuit.
            Valid choices are `text`, `latex`, `latex_source`, `mpl`. By
            default the 'text' drawer is used unless a user config file has
            an alternative backend set as the default. If the output is passed
            in that backend will always be used.
        interactive (bool): when set 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.
        line_length (int): Deprecated. See `fold`.
        reverse_bits (bool): When set to True reverse the bit order inside
            registers for the output visualization.
        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. Currently
            only supported by text drawer.
        vertical_compression (string): `high`, `medium` or `low`. It merges the
            lines generated by `text` so the drawing will take less vertical room.
            Default is `medium`. It is ignored if output is not `text`.
        idle_wires (bool): Include idle wires. Default is True.
        with_layout (bool): Include layout information, with labels on the physical
            layout.
        fold (int): Sets pagination. It can be disabled using -1.
            In `text`, sets the length of the lines. This 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` is the amount of operations before folding. Default is 25.
        ax (matplotlib.axes.Axes): 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. This is only used
            when the ``output`` kwarg is set to use the ``mpl`` backend. It
            will be silently ignored with all other outputs.
    Returns:
        PIL.Image: (output `latex`) an in-memory representation of the image
            of the circuit diagram.
        matplotlib.figure: (output `mpl`) a matplotlib figure object for the
            circuit diagram, if the ``ax`` kwarg is not set
        String: (output `latex_source`). The LaTeX source code.
        TextDrawing: (output `text`). A drawing that can be printed as ascii art
    Raises:
        VisualizationError: when an invalid output method is selected
        ImportError: when the output methods requieres non-installed libraries.

    .. _style-dict-doc:

    The style dict kwarg contains numerous options that define the style of the
    output circuit visualization. While the style dict is used by the `mpl`,
    `latex`, and `latex_source` outputs some options in that are only used
    by the `mpl` output. These options are defined below, if it is only used by
    the `mpl` output it is marked as such:

        textcolor (str): The color code to use for text. Defaults to
            `'#000000'` (`mpl` only)
        subtextcolor (str): The color code to use for subtext. Defaults to
            `'#000000'` (`mpl` only)
        linecolor (str): The color code to use for lines. Defaults to
            `'#000000'` (`mpl` only)
        creglinecolor (str): The color code to use for classical register
            lines. Defaults to `'#778899'`(`mpl` only)
        gatetextcolor (str): The color code to use for gate text. Defaults to
            `'#000000'` (`mpl` only)
        gatefacecolor (str): The color code to use for gates. Defaults to
            `'#ffffff'` (`mpl` only)
        barrierfacecolor (str): The color code to use for barriers. Defaults to
            `'#bdbdbd'` (`mpl` only)
        backgroundcolor (str): The color code to use for the background.
            Defaults to `'#ffffff'` (`mpl` only)
        fontsize (int): The font size to use for text. Defaults to 13 (`mpl`
            only)
        subfontsize (int): The font size to use for subtext. Defaults to 8
            (`mpl` only)
        displaytext (dict): A dictionary of the text to use for each element
            type in the output visualization. The default values are:
            {
                'id': 'id',
                'u0': 'U_0',
                'u1': 'U_1',
                'u2': 'U_2',
                'u3': 'U_3',
                'x': 'X',
                'y': 'Y',
                'z': 'Z',
                'h': 'H',
                's': 'S',
                'sdg': 'S^\\dagger',
                't': 'T',
                'tdg': 'T^\\dagger',
                'rx': 'R_x',
                'ry': 'R_y',
                'rz': 'R_z',
                'reset': '\\left|0\\right\\rangle'
            }
            You must specify all the necessary values if using this. There is
            no provision for passing an incomplete dict in. (`mpl` only)
        displaycolor (dict): The color codes to use for each circuit element.
            The default values are:
            {
                'id': '#F0E442',
                'u0': '#E7AB3B',
                'u1': '#E7AB3B',
                'u2': '#E7AB3B',
                'u3': '#E7AB3B',
                'x': '#58C698',
                'y': '#58C698',
                'z': '#58C698',
                'h': '#70B7EB',
                's': '#E0722D',
                'sdg': '#E0722D',
                't': '#E0722D',
                'tdg': '#E0722D',
                'rx': '#ffffff',
                'ry': '#ffffff',
                'rz': '#ffffff',
                'reset': '#D188B4',
                'target': '#70B7EB',
                'meas': '#D188B4'
           }
           Also, just like  `displaytext` there is no provision for an
           incomplete dict passed in. (`mpl` only)
        latexdrawerstyle (bool): When set to True enable latex mode which will
            draw gates like the `latex` output modes. (`mpl` only)
        usepiformat (bool): When set to True use radians for output (`mpl`
            only)
        fold (int): The number of circuit elements to fold the circuit at.
            Defaults to 20 (`mpl` only)
        cregbundle (bool): If set True bundle classical registers (`mpl` only)
        showindex (bool): If set True draw an index. (`mpl` only)
        compress (bool): If set True draw a compressed circuit (`mpl` only)
        figwidth (int): The maximum width (in inches) for the output figure.
            (`mpl` only)
        dpi (int): The DPI to use for the output image. Defaults to 150 (`mpl`
            only)
        margin (list): `mpl` only
        creglinestyle (str): The style of line to use for classical registers.
            Choices are `'solid'`, `'doublet'`, or any valid matplotlib
            `linestyle` kwarg value. Defaults to `doublet`(`mpl` only)
    """
    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,
                                    line_length=line_length,
                                    reverse_bits=reverse_bits,
                                    plot_barriers=plot_barriers,
                                    justify=justify,
                                    vertical_compression=vertical_compression,
                                    idle_wires=idle_wires,
                                    with_layout=with_layout,
                                    fold=fold)
    elif output == 'latex':
        image = _latex_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)
    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)
    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)
    else:
        raise exceptions.VisualizationError(
            'Invalid output type %s selected. The only valid choices '
            'are latex, latex_source, text, and mpl' % output)
    if image and interactive:
        image.show()
    return image
Esempio n. 4
0
    def _build_latex_array(self, aliases=None):
        """Returns an array of strings containing \\LaTeX for this circuit.

        If aliases is not None, aliases contains a dict mapping
        the current qubits in the circuit to new qubit names.
        We will deduce the register names and sizes from aliases.
        """

        # Rename qregs if necessary
        if aliases:
            qregdata = {}
            for q in aliases.values():
                if q[0] not in qregdata:
                    qregdata[q[0]] = q[1] + 1
                elif qregdata[q[0]] < q[1] + 1:
                    qregdata[q[0]] = q[1] + 1
        else:
            qregdata = self.qregs

        column = 1
        for layer in self.ops:
            num_cols_used = 1

            for op in layer:
                if op.condition:
                    mask = self._get_mask(op.condition[0])
                    cl_reg = self.clbit_list[self._ffs(mask)]
                    if_reg = cl_reg.register
                    pos_2 = self.img_regs[cl_reg]
                    if_value = format(op.condition[1],
                                      'b').zfill(self.cregs[if_reg])[::-1]
                if op.name not in [
                        'measure', 'barrier', 'snapshot', 'load', 'save',
                        'noise'
                ]:
                    nm = generate_latex_label(op.name).replace(" ", "\\,")
                    qarglist = op.qargs
                    if aliases is not None:
                        qarglist = map(lambda x: aliases[x], qarglist)
                    if len(qarglist) == 1:
                        pos_1 = self.img_regs[qarglist[0]]

                        if op.condition:
                            mask = self._get_mask(op.condition[0])
                            cl_reg = self.clbit_list[self._ffs(mask)]
                            if_reg = cl_reg.register
                            pos_2 = self.img_regs[cl_reg]

                            if nm == "x":
                                self._latex[pos_1][column] = "\\gate{X}"
                            elif nm == "y":
                                self._latex[pos_1][column] = "\\gate{Y}"
                            elif nm == "z":
                                self._latex[pos_1][column] = "\\gate{Z}"
                            elif nm == "h":
                                self._latex[pos_1][column] = "\\gate{H}"
                            elif nm == "s":
                                self._latex[pos_1][column] = "\\gate{S}"
                            elif nm == "sdg":
                                self._latex[pos_1][column] = "\\gate{S^\\dag}"
                            elif nm == "t":
                                self._latex[pos_1][column] = "\\gate{T}"
                            elif nm == "tdg":
                                self._latex[pos_1][column] = "\\gate{T^\\dag}"
                            elif nm == "u0":
                                self._latex[pos_1][
                                    column] = "\\gate{U_0(%s)}" % (pi_check(
                                        op.op.params[0], output='latex'))
                            elif nm == "u1":
                                self._latex[pos_1][
                                    column] = "\\gate{U_1(%s)}" % (pi_check(
                                        op.op.params[0], output='latex'))
                            elif nm == "u2":
                                self._latex[pos_1][column] = \
                                    "\\gate{U_2\\left(%s,%s\\right)}" % (
                                        pi_check(op.op.params[0], output='latex'),
                                        pi_check(op.op.params[1], output='latex'))
                            elif nm == "u3":
                                self._latex[pos_1][column] = (
                                    "\\gate{U_3(%s,%s,%s)}" %
                                    (pi_check(op.op.params[0], output='latex'),
                                     pi_check(op.op.params[1], output='latex'),
                                     pi_check(op.op.params[2],
                                              output='latex')))
                            elif nm == "rx":
                                self._latex[pos_1][
                                    column] = "\\gate{R_x(%s)}" % (pi_check(
                                        op.op.params[0], output='latex'))
                            elif nm == "ry":
                                self._latex[pos_1][
                                    column] = "\\gate{R_y(%s)}" % (pi_check(
                                        op.op.params[0], output='latex'))
                            elif nm == "rz":
                                self._latex[pos_1][
                                    column] = "\\gate{R_z(%s)}" % (pi_check(
                                        op.op.params[0], output='latex'))
                            else:
                                self._latex[pos_1][column] = ("\\gate{%s}" %
                                                              nm)

                            gap = pos_2 - pos_1
                            for i in range(self.cregs[if_reg]):
                                if if_value[i] == '1':
                                    self._latex[pos_2 + i][column] = \
                                        "\\control \\cw \\cwx[-" + str(gap) + "]"
                                    gap = 1
                                else:
                                    self._latex[pos_2 + i][column] = \
                                        "\\controlo \\cw \\cwx[-" + str(gap) + "]"
                                    gap = 1

                        else:
                            if nm == "x":
                                self._latex[pos_1][column] = "\\gate{X}"
                            elif nm == "y":
                                self._latex[pos_1][column] = "\\gate{Y}"
                            elif nm == "z":
                                self._latex[pos_1][column] = "\\gate{Z}"
                            elif nm == "h":
                                self._latex[pos_1][column] = "\\gate{H}"
                            elif nm == "s":
                                self._latex[pos_1][column] = "\\gate{S}"
                            elif nm == "sdg":
                                self._latex[pos_1][column] = "\\gate{S^\\dag}"
                            elif nm == "t":
                                self._latex[pos_1][column] = "\\gate{T}"
                            elif nm == "tdg":
                                self._latex[pos_1][column] = "\\gate{T^\\dag}"
                            elif nm == "u0":
                                self._latex[pos_1][
                                    column] = "\\gate{U_0(%s)}" % (pi_check(
                                        op.op.params[0], output='latex'))
                            elif nm == "u1":
                                self._latex[pos_1][
                                    column] = "\\gate{U_1(%s)}" % (pi_check(
                                        op.op.params[0], output='latex'))
                            elif nm == "u2":
                                self._latex[pos_1][column] = \
                                    "\\gate{U_2\\left(%s,%s\\right)}" % (
                                        pi_check(op.op.params[0], output='latex'),
                                        pi_check(op.op.params[1], output='latex'))
                            elif nm == "u3":
                                self._latex[pos_1][column] = (
                                    "\\gate{U_3(%s,%s,%s)}" %
                                    (pi_check(op.op.params[0], output='latex'),
                                     pi_check(op.op.params[1], output='latex'),
                                     pi_check(op.op.params[2],
                                              output='latex')))
                            elif nm == "rx":
                                self._latex[pos_1][
                                    column] = "\\gate{R_x(%s)}" % (pi_check(
                                        op.op.params[0], output='latex'))
                            elif nm == "ry":
                                self._latex[pos_1][
                                    column] = "\\gate{R_y(%s)}" % (pi_check(
                                        op.op.params[0], output='latex'))
                            elif nm == "rz":
                                self._latex[pos_1][
                                    column] = "\\gate{R_z(%s)}" % (pi_check(
                                        op.op.params[0], output='latex'))
                            elif nm == "reset":
                                self._latex[pos_1][column] = (
                                    "\\push{\\rule{.6em}{0em}\\ket{0}\\"
                                    "rule{.2em}{0em}} \\qw")
                            else:
                                self._latex[pos_1][column] = ("\\gate{%s}" %
                                                              nm)

                    elif len(qarglist) == 2:
                        pos_1 = self.img_regs[qarglist[0]]
                        pos_2 = self.img_regs[qarglist[1]]

                        if op.condition:
                            pos_3 = self.img_regs[(if_reg, 0)]
                            temp = [pos_1, pos_2, pos_3]
                            temp.sort(key=int)
                            bottom = temp[1]

                            gap = pos_3 - bottom
                            for i in range(self.cregs[if_reg]):
                                if if_value[i] == '1':
                                    self._latex[pos_3 + i][column] = \
                                        "\\control \\cw \\cwx[-" + str(gap) + "]"
                                    gap = 1
                                else:
                                    self._latex[pos_3 + i][column] = \
                                        "\\controlo \\cw \\cwx[-" + str(gap) + "]"
                                    gap = 1

                            if nm == "cx":
                                self._latex[pos_1][column] = \
                                    "\\ctrl{" + str(pos_2 - pos_1) + "}"
                                self._latex[pos_2][column] = "\\targ"
                            elif nm == "cz":
                                self._latex[pos_1][column] = \
                                    "\\ctrl{" + str(pos_2 - pos_1) + "}"
                                self._latex[pos_2][column] = "\\control\\qw"
                            elif nm == "cy":
                                self._latex[pos_1][column] = \
                                    "\\ctrl{" + str(pos_2 - pos_1) + "}"
                                self._latex[pos_2][column] = "\\gate{Y}"
                            elif nm == "ch":
                                self._latex[pos_1][column] = \
                                    "\\ctrl{" + str(pos_2 - pos_1) + "}"
                                self._latex[pos_2][column] = "\\gate{H}"
                            elif nm == "swap":
                                self._latex[pos_1][column] = "\\qswap"
                                self._latex[pos_2][column] = \
                                    "\\qswap \\qwx[" + str(pos_1 - pos_2) + "]"
                            elif nm == "crz":
                                self._latex[pos_1][column] = \
                                    "\\ctrl{" + str(pos_2 - pos_1) + "}"
                                self._latex[pos_2][column] = \
                                    "\\gate{R_z(%s)}" % (pi_check(op.op.params[0], output='latex'))
                            elif nm == "cu1":
                                self._latex[pos_1][column] = "\\ctrl{" + str(
                                    pos_2 - pos_1) + "}"
                                self._latex[pos_2][column] = "\\control \\qw"
                                self._latex[min(pos_1, pos_2)][column + 1] = \
                                    "\\dstick{%s}\\qw" % (pi_check(op.op.params[0], output='latex'))
                                self._latex[max(pos_1,
                                                pos_2)][column + 1] = "\\qw"
                                # this is because this gate takes up 2 columns,
                                # and we have just written to the next column
                                num_cols_used = 2
                            elif nm == "cu3":
                                self._latex[pos_1][column] = \
                                    "\\ctrl{" + str(pos_2 - pos_1) + "}"
                                self._latex[pos_2][column] = \
                                    "\\gate{U_3(%s,%s,%s)}" % \
                                    (pi_check(op.op.params[0], output='latex'),
                                     pi_check(op.op.params[1], output='latex'),
                                     pi_check(op.op.params[2], output='latex'))
                            elif nm == "rzz":
                                self._latex[pos_1][column] = "\\ctrl{" + str(
                                    pos_2 - pos_1) + "}"
                                self._latex[pos_2][column] = "\\control \\qw"
                                # Based on the \cds command of the qcircuit package
                                self._latex[min(pos_1, pos_2)][column + 1] = \
                                    "*+<0em,0em>{\\hphantom{zz()}} \\POS [0,0].[%d,0]=" \
                                    "\"e\",!C *{zz(%s)};\"e\"+ R \\qw" %\
                                    (max(pos_1, pos_2), pi_check(op.op.params[0], output='latex'))
                                self._latex[max(pos_1,
                                                pos_2)][column + 1] = "\\qw"
                                num_cols_used = 2
                        else:
                            temp = [pos_1, pos_2]
                            temp.sort(key=int)

                            if nm == "cx":
                                self._latex[pos_1][column] = "\\ctrl{" + str(
                                    pos_2 - pos_1) + "}"
                                self._latex[pos_2][column] = "\\targ"
                            elif nm == "cz":
                                self._latex[pos_1][column] = "\\ctrl{" + str(
                                    pos_2 - pos_1) + "}"
                                self._latex[pos_2][column] = "\\control\\qw"
                            elif nm == "cy":
                                self._latex[pos_1][column] = "\\ctrl{" + str(
                                    pos_2 - pos_1) + "}"
                                self._latex[pos_2][column] = "\\gate{Y}"
                            elif nm == "ch":
                                self._latex[pos_1][column] = "\\ctrl{" + str(
                                    pos_2 - pos_1) + "}"
                                self._latex[pos_2][column] = "\\gate{H}"
                            elif nm == "swap":
                                self._latex[pos_1][column] = "\\qswap"
                                self._latex[pos_2][column] = \
                                    "\\qswap \\qwx[" + str(pos_1 - pos_2) + "]"
                            elif nm == "crz":
                                self._latex[pos_1][column] = "\\ctrl{" + str(
                                    pos_2 - pos_1) + "}"
                                self._latex[pos_2][column] = \
                                    "\\gate{R_z(%s)}" % (pi_check(op.op.params[0], output='latex'))
                            elif nm == "cu1":
                                self._latex[pos_1][column] = "\\ctrl{" + str(
                                    pos_2 - pos_1) + "}"
                                self._latex[pos_2][column] = "\\control \\qw"
                                self._latex[min(pos_1, pos_2)][column + 1] = \
                                    "\\dstick{%s}\\qw" % (pi_check(op.op.params[0], output='latex'))
                                self._latex[max(pos_1,
                                                pos_2)][column + 1] = "\\qw"
                                num_cols_used = 2
                            elif nm == "cu3":
                                self._latex[pos_1][column] = "\\ctrl{" + str(
                                    pos_2 - pos_1) + "}"
                                self._latex[pos_2][column] = \
                                    ("\\gate{U_3(%s,%s,%s)}" %
                                     (pi_check(op.op.params[0], output='latex'),
                                      pi_check(op.op.params[1], output='latex'),
                                      pi_check(op.op.params[2], output='latex')))
                            elif nm == "rzz":
                                self._latex[pos_1][column] = "\\ctrl{" + str(
                                    pos_2 - pos_1) + "}"
                                self._latex[pos_2][column] = "\\control \\qw"
                                # Based on the \cds command of the qcircuit package
                                self._latex[min(pos_1, pos_2)][column + 1] = \
                                    "*+<0em,0em>{\\hphantom{zz()}} \\POS [0,0].[%d,0]=" \
                                    "\"e\",!C *{zz(%s)};\"e\"+ R \\qw" %\
                                    (max(pos_1, pos_2), pi_check(op.op.params[0], output='latex'))
                                self._latex[max(pos_1,
                                                pos_2)][column + 1] = "\\qw"
                                num_cols_used = 2
                            else:
                                start_pos = min([pos_1, pos_2])
                                stop_pos = max([pos_1, pos_2])
                                if stop_pos - start_pos >= 2:
                                    delta = stop_pos - start_pos
                                    self._latex[start_pos][column] = (
                                        "\\multigate{%s}{%s}" % (delta, nm))
                                    for i_pos in range(start_pos + 1,
                                                       stop_pos + 1):
                                        self._latex[i_pos][column] = (
                                            "\\ghost{%s}" % nm)
                                else:
                                    self._latex[start_pos][column] = (
                                        "\\multigate{1}{%s}" % nm)
                                    self._latex[stop_pos][column] = (
                                        "\\ghost{%s}" % nm)

                    elif len(qarglist) == 3:
                        pos_1 = self.img_regs[qarglist[0]]
                        pos_2 = self.img_regs[qarglist[1]]
                        pos_3 = self.img_regs[qarglist[2]]

                        if op.condition:
                            pos_4 = self.img_regs[(if_reg, 0)]
                            temp = [pos_1, pos_2, pos_3, pos_4]
                            temp.sort(key=int)
                            bottom = temp[2]

                            gap = pos_4 - bottom
                            for i in range(self.cregs[if_reg]):
                                if if_value[i] == '1':
                                    self._latex[pos_4 + i][column] = \
                                        "\\control \\cw \\cwx[-" + str(gap) + "]"
                                    gap = 1
                                else:
                                    self._latex[pos_4 + i][column] = \
                                        "\\controlo \\cw \\cwx[-" + str(gap) + "]"
                                    gap = 1

                            if nm == "ccx":
                                self._latex[pos_1][column] = "\\ctrl{" + str(
                                    pos_2 - pos_1) + "}"
                                self._latex[pos_2][column] = "\\ctrl{" + str(
                                    pos_3 - pos_2) + "}"
                                self._latex[pos_3][column] = "\\targ"

                            if nm == "cswap":
                                self._latex[pos_1][column] = "\\ctrl{" + str(
                                    pos_2 - pos_1) + "}"
                                self._latex[pos_2][column] = "\\qswap"
                                self._latex[pos_3][column] = \
                                    "\\qswap \\qwx[" + str(pos_2 - pos_3) + "]"
                        else:
                            if nm == "ccx":
                                self._latex[pos_1][column] = "\\ctrl{" + str(
                                    pos_2 - pos_1) + "}"
                                self._latex[pos_2][column] = "\\ctrl{" + str(
                                    pos_3 - pos_2) + "}"
                                self._latex[pos_3][column] = "\\targ"

                            elif nm == "cswap":
                                self._latex[pos_1][column] = "\\ctrl{" + str(
                                    pos_2 - pos_1) + "}"
                                self._latex[pos_2][column] = "\\qswap"
                                self._latex[pos_3][column] = \
                                    "\\qswap \\qwx[" + str(pos_2 - pos_3) + "]"
                            else:
                                start_pos = min([pos_1, pos_2, pos_3])
                                stop_pos = max([pos_1, pos_2, pos_3])
                                if stop_pos - start_pos >= 3:
                                    delta = stop_pos - start_pos
                                    self._latex[start_pos][column] = (
                                        "\\multigate{%s}{%s}" % (delta, nm))
                                    for i_pos in range(start_pos + 1,
                                                       stop_pos + 1):
                                        self._latex[i_pos][column] = (
                                            "\\ghost{%s}" % nm)
                                else:
                                    self._latex[pos_1][column] = (
                                        "\\multigate{2}{%s}" % nm)
                                    self._latex[pos_2][column] = (
                                        "\\ghost{%s}" % nm)
                                    self._latex[pos_3][column] = (
                                        "\\ghost{%s}" % nm)

                    elif len(qarglist) > 3:
                        nbits = len(qarglist)
                        pos_array = [self.img_regs[qarglist[0]]]
                        for i in range(1, nbits):
                            pos_array.append(self.img_regs[qarglist[i]])
                        pos_start = min(pos_array)
                        pos_stop = max(pos_array)
                        self._latex[pos_start][column] = (
                            "\\multigate{%s}{%s}" % (nbits - 1, nm))
                        for pos in range(pos_start + 1, pos_stop + 1):
                            self._latex[pos][column] = ("\\ghost{%s}" % nm)

                elif op.name == "measure":
                    if (len(op.cargs) != 1 or len(op.qargs) != 1
                            or op.op.params):
                        raise exceptions.VisualizationError(
                            "bad operation record")

                    if op.condition:
                        raise exceptions.VisualizationError(
                            "If controlled measures currently not supported.")

                    if aliases:
                        newq = aliases[(qname, qindex)]
                        qname = newq[0]
                        qindex = newq[1]

                    pos_1 = self.img_regs[op.qargs[0]]
                    pos_2 = self.img_regs[op.cargs[0]]

                    try:
                        self._latex[pos_1][column] = "\\meter"
                        self._latex[pos_2][column] = \
                            "\\cw \\cwx[-" + str(pos_2 - pos_1) + "]"
                    except Exception as e:
                        raise exceptions.VisualizationError(
                            'Error during Latex building: %s' % str(e))

                elif op.name in [
                        'barrier', 'snapshot', 'load', 'save', 'noise'
                ]:
                    if self.plot_barriers:
                        qarglist = op.qargs
                        indexes = [self._get_qubit_index(x) for x in qarglist]
                        indexes.sort()
                        if aliases is not None:
                            qarglist = map(lambda x: aliases[x], qarglist)

                        first = last = indexes[0]
                        for index in indexes[1:]:
                            if index - 1 == last:
                                last = index
                            else:
                                pos = self.img_regs[self.qubit_list[first]]
                                self._latex[pos][
                                    column -
                                    1] += " \\barrier[0em]{" + str(last -
                                                                   first) + "}"
                                self._latex[pos][column] = "\\qw"
                                first = last = index
                        pos = self.img_regs[self.qubit_list[first]]
                        self._latex[pos][
                            column -
                            1] += " \\barrier[0em]{" + str(last - first) + "}"
                        self._latex[pos][column] = "\\qw"
                else:
                    raise exceptions.VisualizationError("bad node data")

            # increase the number of columns by the number of columns this layer used
            column += num_cols_used
Esempio n. 5
0
    def _draw_ops(self, verbose=False):
        _wide_gate = ['u2', 'u3', 'cu2', 'cu3', 'unitary', 'r']
        _barriers = {'coord': [], 'group': []}

        #
        # generate coordinate manager
        #
        q_anchors = {}
        for key, qreg in self._qreg_dict.items():
            q_anchors[key] = Anchor(reg_num=self._cond['n_lines'],
                                    yind=qreg['y'],
                                    fold=self.fold)
        c_anchors = {}
        for key, creg in self._creg_dict.items():
            c_anchors[key] = Anchor(reg_num=self._cond['n_lines'],
                                    yind=creg['y'],
                                    fold=self.fold)
        #
        # draw gates
        #
        prev_anc = -1
        for layer in self._ops:
            layer_width = 1

            for op in layer:

                if op.name in _wide_gate:
                    if op.type == 'op' and hasattr(op.op, 'params'):
                        param = self.param_parse(op.op.params)
                        if '$\\pi$' in param:
                            pi_count = param.count('pi')
                            len_param = len(param) - (5 * pi_count)
                        else:
                            len_param = len(param)
                        if len_param > len(op.name):
                            box_width = round(len(param) / 10)
                            # If more than 4 characters min width is 2
                            if box_width <= 1:
                                box_width = 2
                            if layer_width < box_width:
                                if box_width > 2:
                                    layer_width = box_width * 2
                                else:
                                    layer_width = 2
                    if layer_width < 2:
                        layer_width = 2

                # if custom gate with a longer than standard name determine
                # width
                elif op.name not in ['barrier', 'snapshot', 'load', 'save',
                                     'noise', 'cswap', 'swap', 'measure'] and len(
                                         op.name) >= 4:
                    box_width = math.ceil(len(op.name) / 6)

                    # handle params/subtext longer than op names
                    if op.type == 'op' and hasattr(op.op, 'params'):
                        param = self.param_parse(op.op.params)
                        if '$\\pi$' in param:
                            pi_count = param.count('pi')
                            len_param = len(param) - (5 * pi_count)
                        else:
                            len_param = len(param)
                        if len_param > len(op.name):
                            box_width = round(len(param) / 8)
                            # If more than 4 characters min width is 2
                            if box_width <= 1:
                                box_width = 2
                            if layer_width < box_width:
                                if box_width > 2:
                                    layer_width = box_width * 2
                                else:
                                    layer_width = 2
                            continue
                    # If more than 4 characters min width is 2
                    layer_width = math.ceil(box_width * WID * 2.5)

            this_anc = prev_anc + 1

            for op in layer:

                _iswide = op.name in _wide_gate
                if op.name not in ['barrier', 'snapshot', 'load', 'save',
                                   'noise', 'cswap', 'swap', 'measure',
                                   'reset'] and len(op.name) >= 4:
                    _iswide = True

                # get qreg index
                q_idxs = []
                for qarg in op.qargs:
                    for index, reg in self._qreg_dict.items():
                        if (reg['group'] == qarg.register and
                                reg['index'] == qarg.index):
                            q_idxs.append(index)
                            break

                # get creg index
                c_idxs = []
                for carg in op.cargs:
                    for index, reg in self._creg_dict.items():
                        if (reg['group'] == carg.register and
                                reg['index'] == carg.index):
                            c_idxs.append(index)
                            break

                # Only add the gate to the anchors if it is going to be plotted.
                # This prevents additional blank wires at the end of the line if
                # the last instruction is a barrier type
                if self.plot_barriers or \
                        op.name not in ['barrier', 'snapshot', 'load', 'save',
                                        'noise']:

                    for ii in q_idxs:
                        q_anchors[ii].set_index(this_anc, layer_width)

                # qreg coordinate
                q_xy = [q_anchors[ii].plot_coord(this_anc, layer_width, self.x_offset)
                        for ii in q_idxs]
                # creg coordinate
                c_xy = [c_anchors[ii].plot_coord(this_anc, layer_width, self.x_offset)
                        for ii in c_idxs]
                # bottom and top point of qreg
                qreg_b = min(q_xy, key=lambda xy: xy[1])
                qreg_t = max(q_xy, key=lambda xy: xy[1])

                # update index based on the value from plotting
                this_anc = q_anchors[q_idxs[0]].gate_anchor

                if verbose:
                    print(op)

                if op.type == 'op' and hasattr(op.op, 'params'):
                    param = self.param_parse(op.op.params)
                else:
                    param = None
                # conditional gate
                if op.condition:
                    c_xy = [c_anchors[ii].plot_coord(this_anc, layer_width, self.x_offset) for
                            ii in self._creg_dict]
                    mask = 0
                    for index, cbit in enumerate(self._creg):
                        if cbit.register == op.condition[0]:
                            mask |= (1 << index)
                    val = op.condition[1]
                    # cbit list to consider
                    fmt_c = '{{:0{}b}}'.format(len(c_xy))
                    cmask = list(fmt_c.format(mask))[::-1]
                    # value
                    fmt_v = '{{:0{}b}}'.format(cmask.count('1'))
                    vlist = list(fmt_v.format(val))[::-1]
                    # plot conditionals
                    v_ind = 0
                    xy_plot = []
                    for xy, m in zip(c_xy, cmask):
                        if m == '1':
                            if xy not in xy_plot:
                                if vlist[v_ind] == '1' or self._style.bundle:
                                    self._conds(xy, istrue=True)
                                else:
                                    self._conds(xy, istrue=False)
                                xy_plot.append(xy)
                            v_ind += 1
                    creg_b = sorted(xy_plot, key=lambda xy: xy[1])[0]
                    self._subtext(creg_b, hex(val))
                    self._line(qreg_t, creg_b, lc=self._style.cc,
                               ls=self._style.cline)
                #
                # draw special gates
                #
                if op.name == 'measure':
                    vv = self._creg_dict[c_idxs[0]]['index']
                    self._measure(q_xy[0], c_xy[0], vv)
                elif op.name in ['barrier', 'snapshot', 'load', 'save',
                                 'noise']:
                    _barriers = {'coord': [], 'group': []}
                    for index, qbit in enumerate(q_idxs):
                        q_group = self._qreg_dict[qbit]['group']

                        if q_group not in _barriers['group']:
                            _barriers['group'].append(q_group)
                        _barriers['coord'].append(q_xy[index])
                    if self.plot_barriers:
                        self._barrier(_barriers, this_anc)
                elif op.name == 'initialize':
                    vec = '[%s]' % param
                    self._custom_multiqubit_gate(q_xy, wide=_iswide,
                                                 text="|psi>",
                                                 subtext=vec)
                elif op.name == 'unitary':
                    # TODO(mtreinish): Look into adding the unitary to the
                    # subtext
                    self._custom_multiqubit_gate(q_xy, wide=_iswide,
                                                 text="U")
                #
                # draw single qubit gates
                #
                elif len(q_xy) == 1:
                    disp = op.name
                    if param:
                        self._gate(q_xy[0], wide=_iswide, text=disp,
                                   subtext=str(param))
                    else:
                        self._gate(q_xy[0], wide=_iswide, text=disp)
                #
                # draw multi-qubit gates (n=2)
                #
                elif len(q_xy) == 2:
                    # cx
                    if op.name == 'cx':
                        if self._style.dispcol['cx'] != '#ffffff':
                            add_width = self._style.colored_add_width
                        else:
                            add_width = None
                        self._ctrl_qubit(q_xy[0], fc=self._style.dispcol['cx'],
                                         ec=self._style.dispcol['cx'])
                        if self._style.name != 'bw':
                            self._tgt_qubit(q_xy[1], fc=self._style.dispcol['cx'],
                                            ec=self._style.dispcol['cx'],
                                            ac=self._style.dispcol['target'],
                                            add_width=add_width)
                        else:
                            self._tgt_qubit(q_xy[1], fc=self._style.dispcol['target'],
                                            ec=self._style.dispcol['cx'],
                                            ac=self._style.dispcol['cx'],
                                            add_width=add_width)
                        # add qubit-qubit wiring
                        self._line(qreg_b, qreg_t, lc=self._style.dispcol['cx'])
                    # cz for latexmode
                    elif op.name == 'cz':
                        disp = op.name.replace('c', '')
                        if self._style.name != 'bw':
                            color = self._style.dispcol['multi']
                            self._ctrl_qubit(q_xy[0],
                                             fc=color,
                                             ec=color)
                        else:
                            self._ctrl_qubit(q_xy[0])
                        self._gate(q_xy[1], wide=_iswide, text=disp, fc=color)
                        # add qubit-qubit wiring
                        if self._style.name != 'bw':
                            self._line(qreg_b, qreg_t,
                                       lc=self._style.dispcol['multi'])
                        else:
                            self._line(qreg_b, qreg_t, zorder=PORDER_LINE+1)
                    # control gate
                    elif op.name in ['cy', 'ch', 'cu3', 'cu1', 'crz']:
                        disp = op.name.replace('c', '')

                        color = None
                        if self._style.name != 'bw':
                            color = self._style.dispcol['multi']

                        self._ctrl_qubit(q_xy[0], fc=color, ec=color)
                        if param:
                            self._gate(q_xy[1], wide=_iswide,
                                       text=disp,
                                       fc=color,
                                       subtext='{}'.format(param))
                        else:
                            self._gate(q_xy[1], wide=_iswide, text=disp,
                                       fc=color)
                        # add qubit-qubit wiring
                        self._line(qreg_b, qreg_t, lc=color)

                    # rzz gate
                    elif op.name == 'rzz':
                        self._ctrl_qubit(q_xy[0])
                        self._ctrl_qubit(q_xy[1])
                        self._sidetext(qreg_b, text='zz({})'.format(param))

                        # add qubit-qubit wiring
                        self._line(qreg_b, qreg_t)
                    # swap gate
                    elif op.name == 'swap':
                        self._swap(q_xy[0])
                        self._swap(q_xy[1])
                        # add qubit-qubit wiring
                        self._line(qreg_b, qreg_t, lc=self._style.dispcol['swap'])
                    # Custom gate
                    else:
                        self._custom_multiqubit_gate(q_xy, c_xy, wide=_iswide,
                                                     text=op.name)
                #
                # draw multi-qubit gates (n=3)
                #
                elif len(q_xy) == 3:
                    # cswap gate
                    if op.name == 'cswap':
                        self._ctrl_qubit(q_xy[0],
                                         fc=self._style.dispcol['multi'],
                                         ec=self._style.dispcol['multi'])
                        self._swap(q_xy[1])
                        self._swap(q_xy[2])
                        # add qubit-qubit wiring
                        self._line(qreg_b, qreg_t, lc=self._style.dispcol['multi'])
                    # ccx gate
                    elif op.name == 'ccx':
                        self._ctrl_qubit(q_xy[0], fc=self._style.dispcol['multi'],
                                         ec=self._style.dispcol['multi'])
                        self._ctrl_qubit(q_xy[1], fc=self._style.dispcol['multi'],
                                         ec=self._style.dispcol['multi'])
                        if self._style.name != 'bw':
                            self._tgt_qubit(q_xy[2], fc=self._style.dispcol['multi'],
                                            ec=self._style.dispcol['multi'],
                                            ac=self._style.dispcol['target'])
                        else:
                            self._tgt_qubit(q_xy[2], fc=self._style.dispcol['target'],
                                            ec=self._style.dispcol['multi'],
                                            ac=self._style.dispcol['multi'])
                        # add qubit-qubit wiring
                        self._line(qreg_b, qreg_t, lc=self._style.dispcol['multi'])
                    # custom gate
                    else:
                        self._custom_multiqubit_gate(q_xy, c_xy, wide=_iswide,
                                                     text=op.name)

                # draw custom multi-qubit gate
                elif len(q_xy) > 3:
                    self._custom_multiqubit_gate(q_xy, c_xy, wide=_iswide,
                                                 text=op.name)
                else:
                    logger.critical('Invalid gate %s', op)
                    raise exceptions.VisualizationError('invalid gate {}'.format(op))

            # adjust the column if there have been barriers encountered, but not plotted
            barrier_offset = 0
            if not self.plot_barriers:
                # only adjust if everything in the layer wasn't plotted
                barrier_offset = -1 if all([op.name in
                                            ['barrier', 'snapshot', 'load', 'save', 'noise']
                                            for op in layer]) else 0
            prev_anc = this_anc + layer_width + barrier_offset - 1
        #
        # adjust window size and draw horizontal lines
        #
        anchors = [q_anchors[ii].get_index() for ii in self._qreg_dict]
        if anchors:
            max_anc = max(anchors)
        else:
            max_anc = 0
        n_fold = max(0, max_anc - 1) // self.fold
        # window size
        if max_anc > self.fold > 0:
            self._cond['xmax'] = self.fold + 1 + self.x_offset
            self._cond['ymax'] = (n_fold + 1) * (self._cond['n_lines'] + 1) - 1
        else:
            self._cond['xmax'] = max_anc + 1 + self.x_offset
            self._cond['ymax'] = self._cond['n_lines']
        # add horizontal lines
        for ii in range(n_fold + 1):
            feedline_r = (n_fold > 0 and n_fold > ii)
            feedline_l = (ii > 0)
            self._draw_regs_sub(ii, feedline_l, feedline_r)
        # draw gate number
        if self._style.index:
            for ii in range(max_anc):
                if self.fold > 0:
                    x_coord = ii % self.fold + 1
                    y_coord = - (ii // self.fold) * (self._cond['n_lines'] + 1) + 0.7
                else:
                    x_coord = ii + 1
                    y_coord = 0.7
                self.ax.text(x_coord, y_coord, str(ii + 1), ha='center',
                             va='center', fontsize=self._style.sfs,
                             color=self._style.tc, clip_on=True,
                             zorder=PORDER_TEXT)
Esempio n. 6
0
    def _build_latex_array(self, aliases=None):
        """Returns an array of strings containing \\LaTeX for this circuit.

        If aliases is not None, aliases contains a dict mapping
        the current qubits in the circuit to new qubit names.
        We will deduce the register names and sizes from aliases.
        """

        # Rename qregs if necessary
        if aliases:
            qregdata = {}
            for q in aliases.values():
                if q[0] not in qregdata:
                    qregdata[q[0]] = q[1] + 1
                elif qregdata[q[0]] < q[1] + 1:
                    qregdata[q[0]] = q[1] + 1
        else:
            qregdata = self.qregs

        for column, layer in enumerate(self.ops, 1):
            for op in layer:
                if op.condition:
                    mask = self._get_mask(op.condition[0])
                    cl_reg = self.clbit_list[self._ffs(mask)]
                    if_reg = cl_reg[0]
                    pos_2 = self.img_regs[cl_reg]
                    if_value = format(op.condition[1],
                                      'b').zfill(self.cregs[if_reg])[::-1]
                if op.name not in [
                        'measure', 'barrier', 'snapshot', 'load', 'save',
                        'noise'
                ]:
                    nm = op.name
                    qarglist = op.qargs
                    if aliases is not None:
                        qarglist = map(lambda x: aliases[x], qarglist)
                    if len(qarglist) == 1:
                        pos_1 = self.img_regs[(qarglist[0][0], qarglist[0][1])]

                        if op.condition:
                            mask = self._get_mask(op.condition[0])
                            cl_reg = self.clbit_list[self._ffs(mask)]
                            if_reg = cl_reg[0]
                            pos_2 = self.img_regs[cl_reg]

                            if nm == "x":
                                self._latex[pos_1][column] = "\\gate{X}"
                            elif nm == "y":
                                self._latex[pos_1][column] = "\\gate{Y}"
                            elif nm == "z":
                                self._latex[pos_1][column] = "\\gate{Z}"
                            elif nm == "h":
                                self._latex[pos_1][column] = "\\gate{H}"
                            elif nm == "s":
                                self._latex[pos_1][column] = "\\gate{S}"
                            elif nm == "sdg":
                                self._latex[pos_1][column] = "\\gate{S^\\dag}"
                            elif nm == "t":
                                self._latex[pos_1][column] = "\\gate{T}"
                            elif nm == "tdg":
                                self._latex[pos_1][column] = "\\gate{T^\\dag}"
                            elif nm == "u0":
                                self._latex[pos_1][
                                    column] = "\\gate{U_0(%s)}" % (
                                        op.op.params[0])
                            elif nm == "u1":
                                self._latex[pos_1][
                                    column] = "\\gate{U_1(%s)}" % (
                                        op.op.params[0])
                            elif nm == "u2":
                                self._latex[pos_1][column] = \
                                    "\\gate{U_2\\left(%s,%s\\right)}" % (
                                        op.op.params[0], op.op.params[1])
                            elif nm == "u3":
                                self._latex[pos_1][column] = (
                                    "\\gate{U_3(%s,%s,%s)}" %
                                    (op.op.params[0], op.op.params[1],
                                     op.op.params[2]))
                            elif nm == "rx":
                                self._latex[pos_1][
                                    column] = "\\gate{R_x(%s)}" % (
                                        op.op.params[0])
                            elif nm == "ry":
                                self._latex[pos_1][
                                    column] = "\\gate{R_y(%s)}" % (
                                        op.op.params[0])
                            elif nm == "rz":
                                self._latex[pos_1][
                                    column] = "\\gate{R_z(%s)}" % (
                                        op.op.params[0])
                            else:
                                self._latex[pos_1][column] = ("\\gate{%s}" %
                                                              utf8tolatex(nm))

                            gap = pos_2 - pos_1
                            for i in range(self.cregs[if_reg]):
                                if if_value[i] == '1':
                                    self._latex[pos_2 + i][column] = \
                                        "\\control \\cw \\cwx[-" + str(gap) + "]"
                                    gap = 1
                                else:
                                    self._latex[pos_2 + i][column] = \
                                        "\\controlo \\cw \\cwx[-" + str(gap) + "]"
                                    gap = 1

                        else:
                            if nm == "x":
                                self._latex[pos_1][column] = "\\gate{X}"
                            elif nm == "y":
                                self._latex[pos_1][column] = "\\gate{Y}"
                            elif nm == "z":
                                self._latex[pos_1][column] = "\\gate{Z}"
                            elif nm == "h":
                                self._latex[pos_1][column] = "\\gate{H}"
                            elif nm == "s":
                                self._latex[pos_1][column] = "\\gate{S}"
                            elif nm == "sdg":
                                self._latex[pos_1][column] = "\\gate{S^\\dag}"
                            elif nm == "t":
                                self._latex[pos_1][column] = "\\gate{T}"
                            elif nm == "tdg":
                                self._latex[pos_1][column] = "\\gate{T^\\dag}"
                            elif nm == "u0":
                                self._latex[pos_1][
                                    column] = "\\gate{U_0(%s)}" % (
                                        op.op.params[0])
                            elif nm == "u1":
                                self._latex[pos_1][
                                    column] = "\\gate{U_1(%s)}" % (
                                        op.op.params[0])
                            elif nm == "u2":
                                self._latex[pos_1][column] = \
                                    "\\gate{U_2\\left(%s,%s\\right)}" % (
                                        op.op.params[0], op.op.params[1])
                            elif nm == "u3":
                                self._latex[pos_1][column] = (
                                    "\\gate{U_3(%s,%s,%s)}" %
                                    (op.op.params[0], op.op.params[1],
                                     op.op.params[2]))
                            elif nm == "rx":
                                self._latex[pos_1][
                                    column] = "\\gate{R_x(%s)}" % (
                                        op.op.params[0])
                            elif nm == "ry":
                                self._latex[pos_1][
                                    column] = "\\gate{R_y(%s)}" % (
                                        op.op.params[0])
                            elif nm == "rz":
                                self._latex[pos_1][
                                    column] = "\\gate{R_z(%s)}" % (
                                        op.op.params[0])
                            elif nm == "reset":
                                self._latex[pos_1][column] = (
                                    "\\push{\\rule{.6em}{0em}\\ket{0}\\"
                                    "rule{.2em}{0em}} \\qw")
                            else:
                                self._latex[pos_1][column] = ("\\gate{%s}" %
                                                              utf8tolatex(nm))

                    elif len(qarglist) == 2:
                        pos_1 = self.img_regs[(qarglist[0][0], qarglist[0][1])]
                        pos_2 = self.img_regs[(qarglist[1][0], qarglist[1][1])]

                        if op.condition:
                            pos_3 = self.img_regs[(if_reg, 0)]
                            temp = [pos_1, pos_2, pos_3]
                            temp.sort(key=int)
                            bottom = temp[1]

                            gap = pos_3 - bottom
                            for i in range(self.cregs[if_reg]):
                                if if_value[i] == '1':
                                    self._latex[pos_3 + i][column] = \
                                        "\\control \\cw \\cwx[-" + str(gap) + "]"
                                    gap = 1
                                else:
                                    self._latex[pos_3 + i][column] = \
                                        "\\controlo \\cw \\cwx[-" + str(gap) + "]"
                                    gap = 1

                            if nm == "cx":
                                self._latex[pos_1][column] = \
                                    "\\ctrl{" + str(pos_2 - pos_1) + "}"
                                self._latex[pos_2][column] = "\\targ"
                            elif nm == "cz":
                                self._latex[pos_1][column] = \
                                    "\\ctrl{" + str(pos_2 - pos_1) + "}"
                                self._latex[pos_2][column] = "\\control\\qw"
                            elif nm == "cy":
                                self._latex[pos_1][column] = \
                                    "\\ctrl{" + str(pos_2 - pos_1) + "}"
                                self._latex[pos_2][column] = "\\gate{Y}"
                            elif nm == "ch":
                                self._latex[pos_1][column] = \
                                    "\\ctrl{" + str(pos_2 - pos_1) + "}"
                                self._latex[pos_2][column] = "\\gate{H}"
                            elif nm == "swap":
                                self._latex[pos_1][column] = "\\qswap"
                                self._latex[pos_2][column] = \
                                    "\\qswap \\qwx[" + str(pos_1 - pos_2) + "]"
                            elif nm == "crz":
                                self._latex[pos_1][column] = \
                                    "\\ctrl{" + str(pos_2 - pos_1) + "}"
                                self._latex[pos_2][column] = \
                                    "\\gate{R_z(%s)}" % (op.op.params[0])
                            elif nm == "cu1":
                                self._latex[pos_1][
                                    column -
                                    1] = "\\ctrl{" + str(pos_2 - pos_1) + "}"
                                self._latex[pos_2][column -
                                                   1] = "\\control\\qw"
                                self._latex[min(pos_1, pos_2)][column] = \
                                    "\\dstick{%s}\\qw" % (op.op.params[0])
                                self._latex[max(pos_1, pos_2)][column] = "\\qw"
                            elif nm == "cu3":
                                self._latex[pos_1][column] = \
                                    "\\ctrl{" + str(pos_2 - pos_1) + "}"
                                self._latex[pos_2][column] = \
                                    "\\gate{U_3(%s,%s,%s)}" % (op.op.params[0],
                                                               op.op.params[1],
                                                               op.op.params[2])
                        else:
                            temp = [pos_1, pos_2]
                            temp.sort(key=int)

                            if nm == "cx":
                                self._latex[pos_1][column] = "\\ctrl{" + str(
                                    pos_2 - pos_1) + "}"
                                self._latex[pos_2][column] = "\\targ"
                            elif nm == "cz":
                                self._latex[pos_1][column] = "\\ctrl{" + str(
                                    pos_2 - pos_1) + "}"
                                self._latex[pos_2][column] = "\\control\\qw"
                            elif nm == "cy":
                                self._latex[pos_1][column] = "\\ctrl{" + str(
                                    pos_2 - pos_1) + "}"
                                self._latex[pos_2][column] = "\\gate{Y}"
                            elif nm == "ch":
                                self._latex[pos_1][column] = "\\ctrl{" + str(
                                    pos_2 - pos_1) + "}"
                                self._latex[pos_2][column] = "\\gate{H}"
                            elif nm == "swap":
                                self._latex[pos_1][column] = "\\qswap"
                                self._latex[pos_2][column] = \
                                    "\\qswap \\qwx[" + str(pos_1 - pos_2) + "]"
                            elif nm == "crz":
                                self._latex[pos_1][column] = "\\ctrl{" + str(
                                    pos_2 - pos_1) + "}"
                                self._latex[pos_2][column] = \
                                    "\\gate{R_z(%s)}" % (op.op.params[0])
                            elif nm == "cu1":
                                self._latex[pos_1][
                                    column -
                                    1] = "\\ctrl{" + str(pos_2 - pos_1) + "}"
                                self._latex[pos_2][column -
                                                   1] = "\\control\\qw"
                                self._latex[min(pos_1, pos_2)][column] = \
                                    "\\dstick{%s}\\qw" % (op.op.params[0])
                                self._latex[max(pos_1, pos_2)][column] = "\\qw"
                            elif nm == "cu3":
                                self._latex[pos_1][column] = "\\ctrl{" + str(
                                    pos_2 - pos_1) + "}"
                                self._latex[pos_2][column] = (
                                    "\\gate{U_3(%s,%s,%s)}" %
                                    (op.op.params[0], op.op.params[1],
                                     op.op.params[2]))
                            else:
                                start_pos = min([pos_1, pos_2])
                                stop_pos = max([pos_1, pos_2])
                                if stop_pos - start_pos >= 2:
                                    delta = stop_pos - start_pos
                                    self._latex[start_pos][column] = (
                                        "\\multigate{%s}{%s}" %
                                        (delta, utf8tolatex(nm)))
                                    for i_pos in range(start_pos + 1,
                                                       stop_pos + 1):
                                        self._latex[i_pos][column] = (
                                            "\\ghost{%s}" % utf8tolatex(nm))
                                else:
                                    self._latex[start_pos][column] = (
                                        "\\multigate{1}{%s}" % utf8tolatex(nm))
                                    self._latex[stop_pos][column] = (
                                        "\\ghost{%s}" % utf8tolatex(nm))

                    elif len(qarglist) == 3:
                        pos_1 = self.img_regs[(qarglist[0][0], qarglist[0][1])]
                        pos_2 = self.img_regs[(qarglist[1][0], qarglist[1][1])]
                        pos_3 = self.img_regs[(qarglist[2][0], qarglist[2][1])]

                        if op.condition:
                            pos_4 = self.img_regs[(if_reg, 0)]

                            temp = [pos_1, pos_2, pos_3, pos_4]
                            temp.sort(key=int)
                            bottom = temp[2]

                            prev_column = [x[column - 1] for x in self._latex]
                            for item, prev_entry in enumerate(prev_column):
                                if 'barrier' in prev_entry:
                                    span = re.search('barrier{(.*)}',
                                                     prev_entry)
                                    if span and any(i in temp for i in range(
                                            item, int(span.group(1)))):
                                        self._latex[item][column - 1] = \
                                            prev_entry.replace(
                                                '\\barrier{',
                                                '\\barrier[-0.65em]{')

                            gap = pos_4 - bottom
                            for i in range(self.cregs[if_reg]):
                                if if_value[i] == '1':
                                    self._latex[pos_4 + i][column] = \
                                        "\\control \\cw \\cwx[-" + str(gap) + "]"
                                    gap = 1
                                else:
                                    self._latex[pos_4 + i][column] = \
                                        "\\controlo \\cw \\cwx[-" + str(gap) + "]"
                                    gap = 1

                            if nm == "ccx":
                                self._latex[pos_1][column] = "\\ctrl{" + str(
                                    pos_2 - pos_1) + "}"
                                self._latex[pos_2][column] = "\\ctrl{" + str(
                                    pos_3 - pos_2) + "}"
                                self._latex[pos_3][column] = "\\targ"

                            if nm == "cswap":
                                self._latex[pos_1][column] = "\\ctrl{" + str(
                                    pos_2 - pos_1) + "}"
                                self._latex[pos_2][column] = "\\qswap"
                                self._latex[pos_3][column] = \
                                    "\\qswap \\qwx[" + str(pos_2 - pos_3) + "]"
                        else:
                            temp = [pos_1, pos_2, pos_3]
                            temp.sort(key=int)

                            prev_column = [x[column - 1] for x in self._latex]
                            for item, prev_entry in enumerate(prev_column):
                                if 'barrier' in prev_entry:
                                    span = re.search('barrier{(.*)}',
                                                     prev_entry)
                                    if span and any(i in temp for i in range(
                                            item, int(span.group(1)))):
                                        self._latex[item][column - 1] = \
                                            prev_entry.replace(
                                                '\\barrier{',
                                                '\\barrier[-0.65em]{')

                            if nm == "ccx":
                                self._latex[pos_1][column] = "\\ctrl{" + str(
                                    pos_2 - pos_1) + "}"
                                self._latex[pos_2][column] = "\\ctrl{" + str(
                                    pos_3 - pos_2) + "}"
                                self._latex[pos_3][column] = "\\targ"

                            elif nm == "cswap":
                                self._latex[pos_1][column] = "\\ctrl{" + str(
                                    pos_2 - pos_1) + "}"
                                self._latex[pos_2][column] = "\\qswap"
                                self._latex[pos_3][column] = \
                                    "\\qswap \\qwx[" + str(pos_2 - pos_3) + "]"
                            else:
                                start_pos = min([pos_1, pos_2, pos_3])
                                stop_pos = max([pos_1, pos_2, pos_3])
                                if stop_pos - start_pos >= 3:
                                    delta = stop_pos - start_pos
                                    self._latex[start_pos][column] = (
                                        "\\multigate{%s}{%s}" %
                                        (delta, utf8tolatex(nm)))
                                    for i_pos in range(start_pos + 1,
                                                       stop_pos + 1):
                                        self._latex[i_pos][column] = (
                                            "\\ghost{%s}" % utf8tolatex(nm))
                                else:
                                    self._latex[pos_1][column] = (
                                        "\\multigate{2}{%s}" % utf8tolatex(nm))
                                    self._latex[pos_2][column] = (
                                        "\\ghost{%s}" % utf8tolatex(nm))
                                    self._latex[pos_3][column] = (
                                        "\\ghost{%s}" % utf8tolatex(nm))

                    elif len(qarglist) > 3:
                        nbits = len(qarglist)
                        pos_array = [
                            self.img_regs[(qarglist[0][0], qarglist[0][1])]
                        ]
                        for i in range(1, nbits):
                            pos_array.append(self.img_regs[(qarglist[i][0],
                                                            qarglist[i][1])])
                        pos_start = min(pos_array)
                        pos_stop = max(pos_array)
                        delta = pos_stop - pos_start
                        self._latex[pos_start][column] = (
                            "\\multigate{%s}{%s}" %
                            (nbits - 1, utf8tolatex(nm)))
                        for pos in range(pos_start + 1, pos_stop + 1):
                            self._latex[pos][column] = ("\\ghost{%s}" %
                                                        utf8tolatex(nm))

                elif op.name == "measure":
                    if (len(op.cargs) != 1 or len(op.qargs) != 1
                            or op.op.params):
                        raise exceptions.VisualizationError(
                            "bad operation record")

                    if op.condition:
                        raise exceptions.VisualizationError(
                            "If controlled measures currently not supported.")

                    qname, qindex = op.qargs[0]
                    cname, cindex = op.cargs[0]
                    if aliases:
                        newq = aliases[(qname, qindex)]
                        qname = newq[0]
                        qindex = newq[1]

                    pos_1 = self.img_regs[(qname, qindex)]
                    pos_2 = self.img_regs[(cname, cindex)]

                    try:
                        self._latex[pos_1][column] = "\\meter"
                        prev_column = [x[column - 1] for x in self._latex]
                        for item, prev_entry in enumerate(prev_column):
                            if 'barrier' in prev_entry:
                                span = re.search('barrier{(.*)}', prev_entry)
                                if span and (item +
                                             int(span.group(1))) - pos_1 >= 0:
                                    self._latex[item][column - 1] = \
                                        prev_entry.replace(
                                            '\\barrier{',
                                            '\\barrier[-1.15em]{')

                        self._latex[pos_2][column] = \
                            "\\cw \\cwx[-" + str(pos_2 - pos_1) + "]"
                    except Exception as e:
                        raise exceptions.VisualizationError(
                            'Error during Latex building: %s' % str(e))

                elif op.name in [
                        'barrier', 'snapshot', 'load', 'save', 'noise'
                ]:
                    if self.plot_barriers:
                        qarglist = op.qargs
                        indexes = [self._get_qubit_index(x) for x in qarglist]
                        start_bit = self.qubit_list[min(indexes)]
                        if aliases is not None:
                            qarglist = map(lambda x: aliases[x], qarglist)
                        start = self.img_regs[start_bit]
                        span = len(op.qargs) - 1

                        self._latex[start][column] = "\\qw \\barrier{" + str(
                            span) + "}"
                else:
                    raise exceptions.VisualizationError("bad node data")
Esempio n. 7
0
    def _draw_ops(self, verbose=False):
        _wide_gate = ['u2', 'u3', 'cu2', 'cu3']
        _barriers = {'coord': [], 'group': []}

        #
        # generate coordinate manager
        #
        q_anchors = {}
        for key, qreg in self._qreg_dict.items():
            q_anchors[key] = Anchor(reg_num=self._cond['n_lines'],
                                    yind=qreg['y'],
                                    fold=self._style.fold)
        c_anchors = {}
        for key, creg in self._creg_dict.items():
            c_anchors[key] = Anchor(reg_num=self._cond['n_lines'],
                                    yind=creg['y'],
                                    fold=self._style.fold)
        #
        # draw gates
        #
        prev_anc = -1
        for layer in self._ops:
            layer_width = 1

            for op in layer:

                if op.name in _wide_gate:
                    if layer_width < 2:
                        layer_width = 2
                # if custom gate with a longer than standard name determine
                # width
                elif op.name not in [
                        'barrier', 'snapshot', 'load', 'save', 'noise',
                        'cswap', 'swap'
                ] and len(op.name) >= 4:
                    box_width = round(len(op.name) / 8)
                    # If more than 4 characters min width is 2
                    if box_width <= 1:
                        box_width = 2
                    if layer_width < box_width:
                        if box_width > 2:
                            layer_width = box_width * 2
                        else:
                            layer_width = 2

            this_anc = prev_anc + 1

            for op in layer:

                _iswide = op.name in _wide_gate
                if op.name not in [
                        'barrier', 'snapshot', 'load', 'save', 'noise',
                        'cswap', 'swap'
                ] and len(op.name) >= 4:
                    _iswide = True

                # get qreg index
                q_idxs = []
                for qarg in op.qargs:
                    for index, reg in self._qreg_dict.items():
                        if (reg['group'] == qarg[0]
                                and reg['index'] == qarg[1]):
                            q_idxs.append(index)
                            break

                # get creg index
                c_idxs = []
                for carg in op.cargs:
                    for index, reg in self._creg_dict.items():
                        if (reg['group'] == carg[0]
                                and reg['index'] == carg[1]):
                            c_idxs.append(index)
                            break
                for ii in q_idxs:
                    q_anchors[ii].set_index(this_anc, layer_width)

                # qreg coordinate
                q_xy = [
                    q_anchors[ii].plot_coord(this_anc, layer_width)
                    for ii in q_idxs
                ]
                # creg coordinate
                c_xy = [
                    c_anchors[ii].plot_coord(this_anc, layer_width)
                    for ii in c_idxs
                ]
                # bottom and top point of qreg
                qreg_b = min(q_xy, key=lambda xy: xy[1])
                qreg_t = max(q_xy, key=lambda xy: xy[1])

                # update index based on the value from plotting
                this_anc = q_anchors[q_idxs[0]].gate_anchor

                if verbose:
                    print(op)

                if op.type == 'op' and hasattr(op.op, 'params'):
                    param = self.param_parse(op.op.params, self._style.pimode)
                else:
                    param = None
                # conditional gate
                if op.condition:
                    c_xy = [
                        c_anchors[ii].plot_coord(this_anc, layer_width)
                        for ii in self._creg_dict
                    ]
                    mask = 0
                    for index, cbit in enumerate(self._creg):
                        if cbit.reg == op.condition[0]:
                            mask |= (1 << index)
                    val = op.condition[1]
                    # cbit list to consider
                    fmt_c = '{{:0{}b}}'.format(len(c_xy))
                    cmask = list(fmt_c.format(mask))[::-1]
                    # value
                    fmt_v = '{{:0{}b}}'.format(cmask.count('1'))
                    vlist = list(fmt_v.format(val))[::-1]
                    # plot conditionals
                    v_ind = 0
                    xy_plot = []
                    for xy, m in zip(c_xy, cmask):
                        if m == '1':
                            if xy not in xy_plot:
                                if vlist[v_ind] == '1' or self._style.bundle:
                                    self._conds(xy, istrue=True)
                                else:
                                    self._conds(xy, istrue=False)
                                xy_plot.append(xy)
                            v_ind += 1
                    creg_b = sorted(xy_plot, key=lambda xy: xy[1])[0]
                    self._subtext(creg_b, hex(val))
                    self._line(qreg_t,
                               creg_b,
                               lc=self._style.cc,
                               ls=self._style.cline)
                #
                # draw special gates
                #
                if op.name == 'measure':
                    vv = self._creg_dict[c_idxs[0]]['index']
                    self._measure(q_xy[0], c_xy[0], vv)
                elif op.name in [
                        'barrier', 'snapshot', 'load', 'save', 'noise'
                ]:
                    _barriers = {'coord': [], 'group': []}
                    for index, qbit in enumerate(q_idxs):
                        q_group = self._qreg_dict[qbit]['group']

                        if q_group not in _barriers['group']:
                            _barriers['group'].append(q_group)
                        _barriers['coord'].append(q_xy[index])
                    if self.plot_barriers:
                        self._barrier(_barriers, this_anc)
                #
                # draw single qubit gates
                #
                elif len(q_xy) == 1:
                    disp = op.name
                    if param:
                        prm = '{}'.format(param)
                        if len(prm) < 20:
                            self._gate(q_xy[0],
                                       wide=_iswide,
                                       text=disp,
                                       subtext=prm)
                        else:
                            self._gate(q_xy[0], wide=_iswide, text=disp)
                    else:
                        self._gate(q_xy[0], wide=_iswide, text=disp)
                #
                # draw multi-qubit gates (n=2)
                #
                elif len(q_xy) == 2:
                    # cx
                    if op.name == 'cx':
                        self._ctrl_qubit(q_xy[0])
                        self._tgt_qubit(q_xy[1])
                        # add qubit-qubit wiring
                        self._line(qreg_b, qreg_t)
                    # cz for latexmode
                    elif op.name == 'cz':
                        if self._style.latexmode:
                            self._ctrl_qubit(q_xy[0])
                            self._ctrl_qubit(q_xy[1])
                        else:
                            disp = op.name.replace('c', '')
                            self._ctrl_qubit(q_xy[0])
                            self._gate(q_xy[1], wide=_iswide, text=disp)
                        # add qubit-qubit wiring
                        self._line(qreg_b, qreg_t)
                    # control gate
                    elif op.name in ['cy', 'ch', 'cu3', 'crz']:
                        disp = op.name.replace('c', '')
                        self._ctrl_qubit(q_xy[0])
                        if param:
                            self._gate(q_xy[1],
                                       wide=_iswide,
                                       text=disp,
                                       subtext='{}'.format(param))
                        else:
                            self._gate(q_xy[1], wide=_iswide, text=disp)
                        # add qubit-qubit wiring
                        self._line(qreg_b, qreg_t)
                    # cu1 for latexmode
                    elif op.name == 'cu1':
                        disp = op.name.replace('c', '')
                        self._ctrl_qubit(q_xy[0])
                        if self._style.latexmode:
                            self._ctrl_qubit(q_xy[1])
                            self._subtext(qreg_b, param)
                        else:
                            self._gate(q_xy[1],
                                       wide=_iswide,
                                       text=disp,
                                       subtext='{}'.format(param))
                        # add qubit-qubit wiring
                        self._line(qreg_b, qreg_t)
                    # swap gate
                    elif op.name == 'swap':
                        self._swap(q_xy[0])
                        self._swap(q_xy[1])
                        # add qubit-qubit wiring
                        self._line(qreg_b, qreg_t)
                    # Custom gate
                    else:
                        self._custom_multiqubit_gate(q_xy,
                                                     wide=_iswide,
                                                     text=op.name)
                #
                # draw multi-qubit gates (n=3)
                #
                elif len(q_xy) == 3:
                    # cswap gate
                    if op.name == 'cswap':
                        self._ctrl_qubit(q_xy[0])
                        self._swap(q_xy[1])
                        self._swap(q_xy[2])
                        # add qubit-qubit wiring
                        self._line(qreg_b, qreg_t)
                    # ccx gate
                    elif op.name == 'ccx':
                        self._ctrl_qubit(q_xy[0])
                        self._ctrl_qubit(q_xy[1])
                        self._tgt_qubit(q_xy[2])
                        # add qubit-qubit wiring
                        self._line(qreg_b, qreg_t)
                    # custom gate
                    else:
                        self._custom_multiqubit_gate(q_xy,
                                                     wide=_iswide,
                                                     text=op.name)

                # draw custom multi-qubit gate
                elif len(q_xy) > 3:
                    self._custom_multiqubit_gate(q_xy,
                                                 wide=_iswide,
                                                 text=op.name)
                else:
                    logger.critical('Invalid gate %s', op)
                    raise exceptions.VisualizationError(
                        'invalid gate {}'.format(op))

            prev_anc = this_anc + layer_width - 1
        #
        # adjust window size and draw horizontal lines
        #
        anchors = [q_anchors[ii].get_index() for ii in self._qreg_dict]
        if anchors:
            max_anc = max(anchors)
        else:
            max_anc = 0
        n_fold = max(0, max_anc - 1) // self._style.fold
        # window size
        if max_anc > self._style.fold > 0:
            self._cond['xmax'] = self._style.fold + 1
            self._cond['ymax'] = (n_fold + 1) * (self._cond['n_lines'] + 1) - 1
        else:
            self._cond['xmax'] = max_anc + 1
            self._cond['ymax'] = self._cond['n_lines']
        # add horizontal lines
        for ii in range(n_fold + 1):
            feedline_r = (n_fold > 0 and n_fold > ii)
            feedline_l = (ii > 0)
            self._draw_regs_sub(ii, feedline_l, feedline_r)
        # draw gate number
        if self._style.index:
            for ii in range(max_anc):
                if self._style.fold > 0:
                    x_coord = ii % self._style.fold + 1
                    y_coord = -(ii // self._style.fold) * (
                        self._cond['n_lines'] + 1) + 0.7
                else:
                    x_coord = ii + 1
                    y_coord = 0.7
                self.ax.text(x_coord,
                             y_coord,
                             str(ii + 1),
                             ha='center',
                             va='center',
                             fontsize=self._style.sfs,
                             color=self._style.tc,
                             clip_on=True,
                             zorder=PORDER_TEXT)
def circuit_drawer(circuit,
                   scale=0.7,
                   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=False):
    """Draw a quantum circuit to different formats (set by output parameter):

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

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

    **latex_source**: raw uncompiled latex output.

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

    Args:
        circuit (QuantumCircuit): the quantum circuit to draw
        scale (float): scale of image to draw (shrink if < 1). Only used by the ``mpl``,
            ``latex``, and ``latex_source`` outputs.
        filename (str): file path to save image to
        style (dict or str): dictionary of style or file name of style file.
            This option is only used by the ``mpl`` output type. If a str is
            passed in that is the path to a json file which contains that will
            be open, parsed, and then used just as the input dict. See:
            :ref:`Style Dict Doc <style-dict-doc>` for more information on the
            contents.
        output (str): Select the output method to use for drawing the circuit.
            Valid choices are ``text``, ``latex``, ``latex_source``, ``mpl``.
            By default the `'text`' drawer is used unless a user config file
            has an alternative backend set as the default. If the output kwarg
            is set, that backend will always be used over the default in a user
            config file.
        interactive (bool): when set 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.
        reverse_bits (bool): When set to True reverse the bit order inside
            registers for the output visualization.
        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 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): 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. This is only used
            when the ``output`` kwarg is set to use the ``mpl`` backend. It
            will be silently ignored with all other outputs.
        initial_state (bool): Optional. Adds ``|0>`` in the beginning of the wire.
            Default: ``False``.
        cregbundle (bool): Optional. If set True bundle classical registers.
            Default: ``False``.

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

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

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

    .. _style-dict-doc:

    **Style Dict Details**

    The style dict kwarg contains numerous options that define the style of the
    output circuit visualization. The style dict is only used by the ``mpl``
    output. The options available in the style dict are defined below:

    Args:
        textcolor (str): The color code to use for text. Defaults to
            `'#000000'`
        subtextcolor (str): The color code to use for subtext. Defaults to
            `'#000000'`
        linecolor (str): The color code to use for lines. Defaults to
            `'#000000'`
        creglinecolor (str): The color code to use for classical register
            lines. Defaults to `'#778899'`
        gatetextcolor (str): The color code to use for gate text. Defaults to
            `'#000000'`
        gatefacecolor (str): The color code to use for gates. Defaults to
            `'#ffffff'`
        barrierfacecolor (str): The color code to use for barriers. Defaults to
            `'#bdbdbd'`
        backgroundcolor (str): The color code to use for the background.
            Defaults to `'#ffffff'`
        fontsize (int): The font size to use for text. Defaults to 13
        subfontsize (int): The font size to use for subtext. Defaults to 8
        displaytext (dict): A dictionary of the text to use for each element
            type in the output visualization. The default values are::

                {
                    'id': 'id',
                    'u0': 'U_0',
                    'u1': 'U_1',
                    'u2': 'U_2',
                    'u3': 'U_3',
                    'x': 'X',
                    'y': 'Y',
                    'z': 'Z',
                    'h': 'H',
                    's': 'S',
                    'sdg': 'S^\\dagger',
                    't': 'T',
                    'tdg': 'T^\\dagger',
                    'rx': 'R_x',
                    'ry': 'R_y',
                    'rz': 'R_z',
                    'reset': '\\left|0\\right\\rangle'
                }

            You must specify all the necessary values if using this. There is
            no provision for passing an incomplete dict in.
        displaycolor (dict):
            The color codes to use for each circuit element. The default values are::

                {
                    'id': '#F0E442',
                    'u0': '#E7AB3B',
                    'u1': '#E7AB3B',
                    'u2': '#E7AB3B',
                    'u3': '#E7AB3B',
                    'x': '#58C698',
                    'y': '#58C698',
                    'z': '#58C698',
                    'h': '#70B7EB',
                    's': '#E0722D',
                    'sdg': '#E0722D',
                    't': '#E0722D',
                    'tdg': '#E0722D',
                    'rx': '#ffffff',
                    'ry': '#ffffff',
                    'rz': '#ffffff',
                    'reset': '#D188B4',
                    'target': '#70B7EB',
                    'meas': '#D188B4'
                }

           Also, just like  `displaytext` there is no provision for an
           incomplete dict passed in.

        latexdrawerstyle (bool): When set to True enable latex mode which will
            draw gates like the `latex` output modes.
        usepiformat (bool): When set to True use radians for output
        fold (int): The number of circuit elements to fold the circuit at.
            Defaults to 20
        cregbundle (bool): If set True bundle classical registers
        showindex (bool): If set True draw an index.
        compress (bool): If set True draw a compressed circuit
        figwidth (int): The maximum width (in inches) for the output figure.
        dpi (int): The DPI to use for the output image. Defaults to 150
        margin (list): A list of margin values to adjust spacing around output
            image. Takes a list of 4 ints: [x left, x right, y bottom, y top].
        creglinestyle (str): The style of line to use for classical registers.
            Choices are `'solid'`, `'doublet'`, or any valid matplotlib
            `linestyle` kwarg value. Defaults to `doublet`

    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)
    """
    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,
                                      scale=scale,
                                      filename=filename,
                                      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 exceptions.VisualizationError(
            'Invalid output type %s selected. The only valid choices '
            'are latex, latex_source, text, and mpl' % output)
    if image and interactive:
        image.show()
    return image
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` 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
        ImportError: 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,
                                      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,
                                      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 exceptions.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
Esempio n. 10
0
def circuit_drawer(circuit,
                   scale=0.7,
                   filename=None,
                   style=None,
                   output='text',
                   interactive=False,
                   line_length=None,
                   plot_barriers=True,
                   reverse_bits=False,
                   justify=None):
    """Draw a quantum circuit to different formats (set by output parameter):
    0. text: ASCII art TextDrawing that can be printed in the console.
    1. latex: high-quality images, but heavy external software dependencies
    2. matplotlib: purely in Python with no external dependencies

    Args:
        circuit (QuantumCircuit): the quantum circuit to draw
        scale (float): scale of image to draw (shrink if < 1)
        filename (str): file path to save image to
        style (dict or str): dictionary of style or file name of style file.
            This option is only used by the `mpl`, `latex`, and `latex_source`
            output types. If a str is passed in that is the path to a json
            file which contains that will be open, parsed, and then used just
            as the input dict.
        output (TextDrawing): Select the output method to use for drawing the circuit.
            Valid choices are `text`, `latex`, `latex_source`, `mpl`. Note if
            one is not specified it will use latex and if that fails fallback
            to mpl. However this behavior is deprecated and in a future release
            the default will change.
        interactive (bool): when set 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.
        line_length (int): Sets the length of the lines generated by `text`
            output type. This 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 you're running in
            jupyter the default line length is set to 80 characters. If you
            don't want pagination at all, set `line_length=-1`.
        reverse_bits (bool): When set to True reverse the bit order inside
            registers for the output visualization.
        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. Currently
            only supported by text drawer.

    Returns:
        PIL.Image: (output `latex`) an in-memory representation of the image
            of the circuit diagram.
        matplotlib.figure: (output `mpl`) a matplotlib figure object for the
            circuit diagram.
        String: (output `latex_source`). The LaTeX source code.
        TextDrawing: (output `text`). A drawing that can be printed as ascii art
    Raises:
        VisualizationError: when an invalid output method is selected
        ImportError: when the output methods requieres non-installed libraries.

    .. _style-dict-doc:

    The style dict kwarg contains numerous options that define the style of the
    output circuit visualization. While the style dict is used by the `mpl`,
    `latex`, and `latex_source` outputs some options in that are only used
    by the `mpl` output. These options are defined below, if it is only used by
    the `mpl` output it is marked as such:

        textcolor (str): The color code to use for text. Defaults to
            `'#000000'` (`mpl` only)
        subtextcolor (str): The color code to use for subtext. Defaults to
            `'#000000'` (`mpl` only)
        linecolor (str): The color code to use for lines. Defaults to
            `'#000000'` (`mpl` only)
        creglinecolor (str): The color code to use for classical register lines
            `'#778899'`(`mpl` only)
        gatetextcolor (str): The color code to use for gate text `'#000000'`
            (`mpl` only)
        gatefacecolor (str): The color code to use for gates. Defaults to
            `'#ffffff'` (`mpl` only)
        barrierfacecolor (str): The color code to use for barriers. Defaults to
            `'#bdbdbd'` (`mpl` only)
        backgroundcolor (str): The color code to use for the background.
            Defaults to `'#ffffff'` (`mpl` only)
        fontsize (int): The font size to use for text. Defaults to 13 (`mpl`
            only)
        subfontsize (int): The font size to use for subtext. Defaults to 8
            (`mpl` only)
        displaytext (dict): A dictionary of the text to use for each element
            type in the output visualization. The default values are:
            {
                'id': 'id',
                'u0': 'U_0',
                'u1': 'U_1',
                'u2': 'U_2',
                'u3': 'U_3',
                'x': 'X',
                'y': 'Y',
                'z': 'Z',
                'h': 'H',
                's': 'S',
                'sdg': 'S^\\dagger',
                't': 'T',
                'tdg': 'T^\\dagger',
                'rx': 'R_x',
                'ry': 'R_y',
                'rz': 'R_z',
                'reset': '\\left|0\\right\\rangle'
            }
            You must specify all the necessary values if using this. There is
            no provision for passing an incomplete dict in. (`mpl` only)
        displaycolor (dict): The color codes to use for each circuit element.
            By default all values default to the value of `gatefacecolor` and
            the keys are the same as `displaytext`. Also, just like
            `displaytext` there is no provision for an incomplete dict passed
            in. (`mpl` only)
        latexdrawerstyle (bool): When set to True enable latex mode which will
            draw gates like the `latex` output modes. (`mpl` only)
        usepiformat (bool): When set to True use radians for output (`mpl`
            only)
        fold (int): The number of circuit elements to fold the circuit at.
            Defaults to 20 (`mpl` only)
        cregbundle (bool): If set True bundle classical registers (`mpl` only)
        showindex (bool): If set True draw an index. (`mpl` only)
        compress (bool): If set True draw a compressed circuit (`mpl` only)
        figwidth (int): The maximum width (in inches) for the output figure.
            (`mpl` only)
        dpi (int): The DPI to use for the output image. Defaults to 150 (`mpl`
            only)
        margin (list): `mpl` only
        creglinestyle (str): The style of line to use for classical registers.
            Choices are `'solid'`, `'doublet'`, or any valid matplotlib
            `linestyle` kwarg value. Defaults to `doublet`(`mpl` only)
    """
    image = None

    if output == 'text':
        return _text_circuit_drawer(circuit,
                                    filename=filename,
                                    line_length=line_length,
                                    reverse_bits=reverse_bits,
                                    plotbarriers=plot_barriers,
                                    justify=justify)
    elif output == 'latex':
        image = _latex_circuit_drawer(circuit,
                                      scale=scale,
                                      filename=filename,
                                      style=style,
                                      plot_barriers=plot_barriers,
                                      reverse_bits=reverse_bits,
                                      justify=justify)
    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)
    elif output == 'mpl':
        image = _matplotlib_circuit_drawer(circuit,
                                           scale=scale,
                                           filename=filename,
                                           style=style,
                                           plot_barriers=plot_barriers,
                                           reverse_bits=reverse_bits,
                                           justify=justify)
    else:
        raise exceptions.VisualizationError(
            'Invalid output type %s selected. The only valid choices '
            'are latex, latex_source, text, and mpl' % output)
    if image and interactive:
        image.show()
    return image
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` output type. If 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: :ref:`Style Dict Doc <style-dict-doc>` 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
        ImportError: when the output methods requires non-installed libraries.

    .. _style-dict-doc:

    **Style Dict Details**

    The style dict kwarg contains numerous options that define the style of the
    output circuit visualization. The style dict is only used by the `mpl`
    output. The options available in the style dict are defined below:

    Args:
        name (str): the name of the style. The name can be set to ``iqx``,
            ``bw``, ``default``, or the name of a user-created json file. This
            overrides the setting in the user config file (usually
            ``~/.qiskit/settings.conf``).
        textcolor (str): the color code to use for all text not inside a gate.
            Defaults to ``#000000``
        subtextcolor (str): the color code to use for subtext. Defaults to
            ``#000000``
        linecolor (str): the color code to use for lines. Defaults to
            ``#000000``
        creglinecolor (str): the color code to use for classical register
            lines. Defaults to ``#778899``
        gatetextcolor (str): the color code to use for gate text. Defaults to
            ``#000000``
        gatefacecolor (str): the color code to use for a gate if no color
            specified in the 'displaycolor' dict. Defaults to ``#BB8BFF``
        barrierfacecolor (str): the color code to use for barriers. Defaults to
            ``#BDBDBD``
        backgroundcolor (str): the color code to use for the background.
            Defaults to ``#FFFFFF``
        edgecolor (str): the color code to use for gate edges when using the
            `bw` style. Defaults to ``#000000``.
        fontsize (int): the font size to use for text. Defaults to 13.
        subfontsize (int): the font size to use for subtext. Defaults to 8.
        showindex (bool): if set to True, show the index numbers at the top.
            Defaults to False.
        figwidth (int): the maximum width (in inches) for the output figure.
            If set to -1, the maximum displayable width will be used.
            Defaults to -1.
        dpi (int): the DPI to use for the output image. Defaults to 150.
        margin (list): a list of margin values to adjust spacing around output
            image. Takes a list of 4 ints: [x left, x right, y bottom, y top].
            Defaults to [2.0, 0.1, 0.1, 0.3].
        creglinestyle (str): The style of line to use for classical registers.
            Choices are ``solid``, ``doublet``, or any valid matplotlib
            `linestyle` kwarg value. Defaults to ``doublet``.
        displaytext (dict): a dictionary of the text to use for certain element
            types in the output visualization. These items allow the use of
            LaTeX formatting for gate names. The 'displaytext' dict can contain
            any number of elements from one to the entire dict above.The default
            values are (`default.json`)::

                {
                    'u1': '$\\mathrm{U}_1$',
                    'u2': '$\\mathrm{U}_2$',
                    'u3': '$\\mathrm{U}_3$',
                    'u': 'U',
                    'p': 'P',
                    'id': 'I',
                    'x': 'X',
                    'y': 'Y',
                    'z': 'Z',
                    'h': 'H',
                    's': 'S',
                    'sdg': '$\\mathrm{S}^\\dagger$',
                    'sx': '$\\sqrt{\\mathrm{X}}$',
                    'sxdg': '$\\sqrt{\\mathrm{X}}^\\dagger$',
                    't': 'T',
                    'tdg': '$\\mathrm{T}^\\dagger$',
                    'dcx': 'Dcx',
                    'iswap': 'Iswap',
                    'ms': 'MS',
                    'r': 'R',
                    'rx': '$\\mathrm{R}_\\mathrm{X}$',
                    'ry': '$\\mathrm{R}_\\mathrm{Y}$',
                    'rz': '$\\mathrm{R}_\\mathrm{Z}$',
                    'rxx': '$\\mathrm{R}_{\\mathrm{XX}}$',
                    'ryy': '$\\mathrm{R}_{\\mathrm{YY}}$',
                    'rzx': '$\\mathrm{R}_{\\mathrm{ZX}}$',
                    'rzz': '$\\mathrm{R}_{\\mathrm{ZZ}}$',
                    'reset': '$\\left|0\\right\\rangle$',
                    'initialize': '$|\\psi\\rangle$'
                }

        displaycolor (dict): the color codes to use for each circuit element in
            the form (gate_color, text_color). Colors can also be entered without
            the text color, such as 'u1': '#FA74A6', in which case the text color
            will always be `gatetextcolor`. The `displaycolor` dict can contain
            any number of elements from one to the entire dict above. The default
            values are (`default.json`)::

                {
                    'u1': ('#FA74A6', '#000000'),
                    'u2': ('#FA74A6', '#000000'),
                    'u3': ('#FA74A6', '#000000'),
                    'id': ('#05BAB6', '#000000'),
                    'u': ('#BB8BFF', '#000000'),
                    'p': ('#BB8BFF', '#000000'),
                    'x': ('#05BAB6', '#000000'),
                    'y': ('#05BAB6', '#000000'),
                    'z': ('#05BAB6', '#000000'),
                    'h': ('#6FA4FF', '#000000'),
                    'cx': ('#6FA4FF', '#000000'),
                    'ccx': ('#BB8BFF', '#000000'),
                    'mcx': ('#BB8BFF', '#000000'),
                    'mcx_gray': ('#BB8BFF', '#000000),
                    'cy': ('#6FA4FF', '#000000'),
                    'cz': ('#6FA4FF', '#000000'),
                    'swap': ('#6FA4FF', '#000000'),
                    'cswap': ('#BB8BFF', '#000000'),
                    'ccswap': ('#BB8BFF', '#000000'),
                    'dcx': ('#6FA4FF', '#000000'),
                    'cdcx': ('#BB8BFF', '#000000'),
                    'ccdcx': ('#BB8BFF', '#000000'),
                    'iswap': ('#6FA4FF', '#000000'),
                    's': ('#6FA4FF', '#000000'),
                    'sdg': ('#6FA4FF', '#000000'),
                    't': ('#BB8BFF', '#000000'),
                    'tdg': ('#BB8BFF', '#000000'),
                    'sx': ('#BB8BFF', '#000000'),
                    'sxdg': ('#BB8BFF', '#000000')
                    'r': ('#BB8BFF', '#000000'),
                    'rx': ('#BB8BFF', '#000000'),
                    'ry': ('#BB8BFF', '#000000'),
                    'rz': ('#BB8BFF', '#000000'),
                    'rxx': ('#BB8BFF', '#000000'),
                    'ryy': ('#BB8BFF', '#000000'),
                    'rzx': ('#BB8BFF', '#000000'),
                    'reset': ('#000000', #FFFFFF'),
                    'target': ('#FFFFFF, '#FFFFFF'),
                    'measure': ('#000000', '#FFFFFF'),
                }

    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={'showindex': True})
    """
    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,
                                      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,
                                      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 exceptions.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
Esempio n. 12
0
    def _build_latex_array(self, aliases=None):
        """Returns an array of strings containing \\LaTeX for this circuit.

        If aliases is not None, aliases contains a dict mapping
        the current qubits in the circuit to new qubit names.
        We will deduce the register names and sizes from aliases.
        """
        columns = 1
        is_occupied = [False] * self.img_width

        # Rename qregs if necessary
        if aliases:
            qregdata = {}
            for q in aliases.values():
                if q[0] not in qregdata:
                    qregdata[q[0]] = q[1] + 1
                elif qregdata[q[0]] < q[1] + 1:
                    qregdata[q[0]] = q[1] + 1
        else:
            qregdata = self.qregs

        for current_op in self.ops:
            if current_op.condition:
                mask = self._get_mask(current_op.condition[0])
                cl_reg = self.clbit_list[self._ffs(mask)]
                if_reg = cl_reg[0]
                pos_2 = self.img_regs[cl_reg]
                if_value = format(current_op.condition[1],
                                  'b').zfill(self.cregs[if_reg])[::-1]
            if current_op.name not in [
                    'measure', 'barrier', 'snapshot', 'load', 'save', 'noise'
            ]:
                nm = current_op.name
                qarglist = current_op.qargs
                if aliases is not None:
                    qarglist = map(lambda x: aliases[x], qarglist)
                if len(qarglist) == 1:
                    pos_1 = self.img_regs[(qarglist[0][0], qarglist[0][1])]
                    if current_op.condition:
                        mask = self._get_mask(current_op.condition[0])
                        cl_reg = self.clbit_list[self._ffs(mask)]
                        if_reg = cl_reg[0]
                        pos_2 = self.img_regs[cl_reg]
                        for i in range(pos_1, pos_2 + self.cregs[if_reg]):
                            if is_occupied[i] is False:
                                is_occupied[i] = True
                            else:
                                columns += 1
                                is_occupied = [False] * self.img_width
                                for j in range(pos_1, pos_2 + 1):
                                    is_occupied[j] = True
                                break

                        if nm == "x":
                            self._latex[pos_1][columns] = "\\gate{X}"
                        elif nm == "y":
                            self._latex[pos_1][columns] = "\\gate{Y}"
                        elif nm == "z":
                            self._latex[pos_1][columns] = "\\gate{Z}"
                        elif nm == "h":
                            self._latex[pos_1][columns] = "\\gate{H}"
                        elif nm == "id":
                            self._latex[pos_1][columns] = "\\gate{Id}"
                        elif nm == "s":
                            self._latex[pos_1][columns] = "\\gate{S}"
                        elif nm == "sdg":
                            self._latex[pos_1][columns] = "\\gate{S^\\dag}"
                        elif nm == "t":
                            self._latex[pos_1][columns] = "\\gate{T}"
                        elif nm == "tdg":
                            self._latex[pos_1][columns] = "\\gate{T^\\dag}"
                        elif nm == "u0":
                            self._latex[pos_1][columns] = "\\gate{U_0(%s)}" % (
                                current_op.op.params[0])
                        elif nm == "u1":
                            self._latex[pos_1][columns] = "\\gate{U_1(%s)}" % (
                                current_op["op"].params[0])
                        elif nm == "u2":
                            self._latex[pos_1][columns] = \
                                "\\gate{U_2\\left(%s,%s\\right)}" % (
                                    current_op["op"].params[0], current_op["op"].params[1])
                        elif nm == "u3":
                            self._latex[pos_1][columns] = (
                                "\\gate{U_3(%s,%s,%s)}" %
                                (current_op.op.params[0],
                                 current_op.op.params[1],
                                 current_op.op.params[2]))
                        elif nm == "rx":
                            self._latex[pos_1][columns] = "\\gate{R_x(%s)}" % (
                                current_op.op.params[0])
                        elif nm == "ry":
                            self._latex[pos_1][columns] = "\\gate{R_y(%s)}" % (
                                current_op.op.params[0])
                        elif nm == "rz":
                            self._latex[pos_1][columns] = "\\gate{R_z(%s)}" % (
                                current_op.op.params[0])

                        gap = pos_2 - pos_1
                        for i in range(self.cregs[if_reg]):
                            if if_value[i] == '1':
                                self._latex[pos_2 + i][columns] = \
                                    "\\control \\cw \\cwx[-" + str(gap) + "]"
                                gap = 1
                            else:
                                self._latex[pos_2 + i][columns] = \
                                    "\\controlo \\cw \\cwx[-" + str(gap) + "]"
                                gap = 1

                    else:
                        if not is_occupied[pos_1]:
                            is_occupied[pos_1] = True
                        else:
                            columns += 1
                            is_occupied = [False] * self.img_width
                            is_occupied[pos_1] = True

                        if nm == "x":
                            self._latex[pos_1][columns] = "\\gate{X}"
                        elif nm == "y":
                            self._latex[pos_1][columns] = "\\gate{Y}"
                        elif nm == "z":
                            self._latex[pos_1][columns] = "\\gate{Z}"
                        elif nm == "h":
                            self._latex[pos_1][columns] = "\\gate{H}"
                        elif nm == "id":
                            self._latex[pos_1][columns] = "\\gate{Id}"
                        elif nm == "s":
                            self._latex[pos_1][columns] = "\\gate{S}"
                        elif nm == "sdg":
                            self._latex[pos_1][columns] = "\\gate{S^\\dag}"
                        elif nm == "t":
                            self._latex[pos_1][columns] = "\\gate{T}"
                        elif nm == "tdg":
                            self._latex[pos_1][columns] = "\\gate{T^\\dag}"
                        elif nm == "u0":
                            self._latex[pos_1][columns] = "\\gate{U_0(%s)}" % (
                                current_op.op.params[0])
                        elif nm == "u1":
                            self._latex[pos_1][columns] = "\\gate{U_1(%s)}" % (
                                current_op.op.params[0])
                        elif nm == "u2":
                            self._latex[pos_1][columns] = \
                                "\\gate{U_2\\left(%s,%s\\right)}" % (
                                    current_op.op.params[0], current_op.op.params[1])
                        elif nm == "u3":
                            self._latex[pos_1][columns] = (
                                "\\gate{U_3(%s,%s,%s)}" %
                                (current_op.op.params[0],
                                 current_op.op.params[1],
                                 current_op.op.params[2]))
                        elif nm == "rx":
                            self._latex[pos_1][columns] = "\\gate{R_x(%s)}" % (
                                current_op.op.params[0])
                        elif nm == "ry":
                            self._latex[pos_1][columns] = "\\gate{R_y(%s)}" % (
                                current_op.op.params[0])
                        elif nm == "rz":
                            self._latex[pos_1][columns] = "\\gate{R_z(%s)}" % (
                                current_op.op.params[0])
                        elif nm == "reset":
                            self._latex[pos_1][columns] = (
                                "\\push{\\rule{.6em}{0em}\\ket{0}\\"
                                "rule{.2em}{0em}} \\qw")

                elif len(qarglist) == 2:
                    pos_1 = self.img_regs[(qarglist[0][0], qarglist[0][1])]
                    pos_2 = self.img_regs[(qarglist[1][0], qarglist[1][1])]

                    if current_op.condition:
                        pos_3 = self.img_regs[(if_reg, 0)]
                        temp = [pos_1, pos_2, pos_3]
                        temp.sort(key=int)
                        top = temp[0]
                        bottom = temp[1]

                        for i in range(top, pos_3 + 1):
                            if is_occupied[i] is False:
                                is_occupied[i] = True
                            else:
                                columns += 1
                                is_occupied = [False] * self.img_width
                                for j in range(top, pos_3 + 1):
                                    is_occupied[j] = True
                                break
                        # symetric gates have angle labels
                        if current_op.name == 'cu1':
                            columns += 1
                            is_occupied = [False] * self.img_width
                            is_occupied[top] = True

                        gap = pos_3 - bottom
                        for i in range(self.cregs[if_reg]):
                            if if_value[i] == '1':
                                self._latex[pos_3 + i][columns] = \
                                    "\\control \\cw \\cwx[-" + str(gap) + "]"
                                gap = 1
                            else:
                                self._latex[pos_3 + i][columns] = \
                                    "\\controlo \\cw \\cwx[-" + str(gap) + "]"
                                gap = 1

                        if nm == "cx":
                            self._latex[pos_1][columns] = \
                                "\\ctrl{" + str(pos_2 - pos_1) + "}"
                            self._latex[pos_2][columns] = "\\targ"
                        elif nm == "cz":
                            self._latex[pos_1][columns] = \
                                "\\ctrl{" + str(pos_2 - pos_1) + "}"
                            self._latex[pos_2][columns] = "\\control\\qw"
                        elif nm == "cy":
                            self._latex[pos_1][columns] = \
                                "\\ctrl{" + str(pos_2 - pos_1) + "}"
                            self._latex[pos_2][columns] = "\\gate{Y}"
                        elif nm == "ch":
                            self._latex[pos_1][columns] = \
                                "\\ctrl{" + str(pos_2 - pos_1) + "}"
                            self._latex[pos_2][columns] = "\\gate{H}"
                        elif nm == "swap":
                            self._latex[pos_1][columns] = "\\qswap"
                            self._latex[pos_2][columns] = \
                                "\\qswap \\qwx[" + str(pos_1 - pos_2) + "]"
                        elif nm == "crz":
                            self._latex[pos_1][columns] = \
                                "\\ctrl{" + str(pos_2 - pos_1) + "}"
                            self._latex[pos_2][columns] = \
                                "\\gate{R_z(%s)}" % (current_op.op.params[0])
                        elif nm == "cu1":
                            self._latex[pos_1][
                                columns -
                                1] = "\\ctrl{" + str(pos_2 - pos_1) + "}"
                            self._latex[pos_2][columns - 1] = "\\control\\qw"
                            self._latex[min(pos_1, pos_2)][columns] = \
                                "\\dstick{%s}\\qw" % (current_op.op.params[0])
                            self._latex[max(pos_1, pos_2)][columns] = "\\qw"
                        elif nm == "cu3":
                            self._latex[pos_1][columns] = \
                                "\\ctrl{" + str(pos_2 - pos_1) + "}"
                            self._latex[pos_2][columns] = \
                                "\\gate{U_3(%s,%s,%s)}" % (current_op.op.params[0],
                                                           current_op.op.params[1],
                                                           current_op.op.params[2])
                    else:
                        temp = [pos_1, pos_2]
                        temp.sort(key=int)
                        top = temp[0]
                        bottom = temp[1]

                        for i in range(top, bottom + 1):
                            if is_occupied[i] is False:
                                is_occupied[i] = True
                            else:
                                columns += 1
                                is_occupied = [False] * self.img_width
                                for j in range(top, bottom + 1):
                                    is_occupied[j] = True
                                break
                        # symetric gates have angle labels
                        if current_op.name == 'cu1':
                            columns += 1
                            is_occupied = [False] * self.img_width
                            is_occupied[top] = True

                        if nm == "cx":
                            self._latex[pos_1][columns] = "\\ctrl{" + str(
                                pos_2 - pos_1) + "}"
                            self._latex[pos_2][columns] = "\\targ"
                        elif nm == "cz":
                            self._latex[pos_1][columns] = "\\ctrl{" + str(
                                pos_2 - pos_1) + "}"
                            self._latex[pos_2][columns] = "\\control\\qw"
                        elif nm == "cy":
                            self._latex[pos_1][columns] = "\\ctrl{" + str(
                                pos_2 - pos_1) + "}"
                            self._latex[pos_2][columns] = "\\gate{Y}"
                        elif nm == "ch":
                            self._latex[pos_1][columns] = "\\ctrl{" + str(
                                pos_2 - pos_1) + "}"
                            self._latex[pos_2][columns] = "\\gate{H}"
                        elif nm == "swap":
                            self._latex[pos_1][columns] = "\\qswap"
                            self._latex[pos_2][columns] = \
                                "\\qswap \\qwx[" + str(pos_1 - pos_2) + "]"
                        elif nm == "crz":
                            self._latex[pos_1][columns] = "\\ctrl{" + str(
                                pos_2 - pos_1) + "}"
                            self._latex[pos_2][columns] = \
                                "\\gate{R_z(%s)}" % (current_op.op.params[0])
                        elif nm == "cu1":
                            self._latex[pos_1][
                                columns -
                                1] = "\\ctrl{" + str(pos_2 - pos_1) + "}"
                            self._latex[pos_2][columns - 1] = "\\control\\qw"
                            self._latex[min(pos_1, pos_2)][columns] = \
                                "\\dstick{%s}\\qw" % (current_op.op.params[0])
                            self._latex[max(pos_1, pos_2)][columns] = "\\qw"
                        elif nm == "cu3":
                            self._latex[pos_1][columns] = "\\ctrl{" + str(
                                pos_2 - pos_1) + "}"
                            self._latex[pos_2][columns] = (
                                "\\gate{U_3(%s,%s,%s)}" %
                                (current_op.op.params[0],
                                 current_op.op.params[1],
                                 current_op.op.params[2]))

                elif len(qarglist) == 3:
                    pos_1 = self.img_regs[(qarglist[0][0], qarglist[0][1])]
                    pos_2 = self.img_regs[(qarglist[1][0], qarglist[1][1])]
                    pos_3 = self.img_regs[(qarglist[2][0], qarglist[2][1])]

                    if current_op.condition:
                        pos_4 = self.img_regs[(if_reg, 0)]

                        temp = [pos_1, pos_2, pos_3, pos_4]
                        temp.sort(key=int)
                        top = temp[0]
                        bottom = temp[2]

                        for i in range(top, pos_4 + 1):
                            if is_occupied[i] is False:
                                is_occupied[i] = True
                            else:
                                columns += 1
                                is_occupied = [False] * self.img_width
                                for j in range(top, pos_4 + 1):
                                    is_occupied[j] = True
                                break

                        prev_column = [x[columns - 1] for x in self._latex]
                        for item, prev_entry in enumerate(prev_column):
                            if 'barrier' in prev_entry:
                                span = re.search('barrier{(.*)}', prev_entry)
                                if span and any(i in temp for i in range(
                                        item, int(span.group(1)))):
                                    self._latex[item][columns - 1] = \
                                        prev_entry.replace(
                                            '\\barrier{',
                                            '\\barrier[-0.65em]{')

                        gap = pos_4 - bottom
                        for i in range(self.cregs[if_reg]):
                            if if_value[i] == '1':
                                self._latex[pos_4 + i][columns] = \
                                    "\\control \\cw \\cwx[-" + str(gap) + "]"
                                gap = 1
                            else:
                                self._latex[pos_4 + i][columns] = \
                                    "\\controlo \\cw \\cwx[-" + str(gap) + "]"
                                gap = 1

                        if nm == "ccx":
                            self._latex[pos_1][columns] = "\\ctrl{" + str(
                                pos_2 - pos_1) + "}"
                            self._latex[pos_2][columns] = "\\ctrl{" + str(
                                pos_3 - pos_2) + "}"
                            self._latex[pos_3][columns] = "\\targ"

                        if nm == "cswap":
                            self._latex[pos_1][columns] = "\\ctrl{" + str(
                                pos_2 - pos_1) + "}"
                            self._latex[pos_2][columns] = "\\qswap"
                            self._latex[pos_3][columns] = \
                                "\\qswap \\qwx[" + str(pos_2 - pos_3) + "]"
                    else:
                        temp = [pos_1, pos_2, pos_3]
                        temp.sort(key=int)
                        top = temp[0]
                        bottom = temp[2]

                        for i in range(top, bottom + 1):
                            if is_occupied[i] is False:
                                is_occupied[i] = True
                            else:
                                columns += 1
                                is_occupied = [False] * self.img_width
                                for j in range(top, bottom + 1):
                                    is_occupied[j] = True
                                break

                        prev_column = [x[columns - 1] for x in self._latex]
                        for item, prev_entry in enumerate(prev_column):
                            if 'barrier' in prev_entry:
                                span = re.search('barrier{(.*)}', prev_entry)
                                if span and any(i in temp for i in range(
                                        item, int(span.group(1)))):
                                    self._latex[item][columns - 1] = \
                                        prev_entry.replace(
                                            '\\barrier{',
                                            '\\barrier[-0.65em]{')

                        if nm == "ccx":
                            self._latex[pos_1][columns] = "\\ctrl{" + str(
                                pos_2 - pos_1) + "}"
                            self._latex[pos_2][columns] = "\\ctrl{" + str(
                                pos_3 - pos_2) + "}"
                            self._latex[pos_3][columns] = "\\targ"

                        if nm == "cswap":
                            self._latex[pos_1][columns] = "\\ctrl{" + str(
                                pos_2 - pos_1) + "}"
                            self._latex[pos_2][columns] = "\\qswap"
                            self._latex[pos_3][columns] = \
                                "\\qswap \\qwx[" + str(pos_2 - pos_3) + "]"

            elif current_op.name == "measure":
                if (len(current_op.cargs) != 1 or len(current_op.qargs) != 1
                        or current_op.op.params):
                    raise exceptions.VisualizationError("bad operation record")
                if current_op.condition:
                    raise exceptions.VisualizationError(
                        "If controlled measures currently not supported.")

                qname, qindex = current_op.qargs[0]
                cname, cindex = current_op.cargs[0]
                if aliases:
                    newq = aliases[(qname, qindex)]
                    qname = newq[0]
                    qindex = newq[1]

                pos_1 = self.img_regs[(qname, qindex)]
                pos_2 = self.img_regs[(cname, cindex)]

                for i in range(pos_1, pos_2 + 1):
                    if is_occupied[i] is False:
                        is_occupied[i] = True
                    else:
                        columns += 1
                        is_occupied = [False] * self.img_width
                        for j in range(pos_1, pos_2 + 1):
                            is_occupied[j] = True
                        break

                try:
                    self._latex[pos_1][columns] = "\\meter"
                    prev_column = [x[columns - 1] for x in self._latex]
                    for item, prev_entry in enumerate(prev_column):
                        if 'barrier' in prev_entry:
                            span = re.search('barrier{(.*)}', prev_entry)
                            if span and (item +
                                         int(span.group(1))) - pos_1 >= 0:
                                self._latex[item][columns - 1] = \
                                    prev_entry.replace(
                                        '\\barrier{',
                                        '\\barrier[-1.15em]{')

                    self._latex[pos_2][columns] = \
                        "\\cw \\cwx[-" + str(pos_2 - pos_1) + "]"
                except Exception as e:
                    raise exceptions.VisualizationError(
                        'Error during Latex building: %s' % str(e))
            elif current_op.name in [
                    'barrier', 'snapshot', 'load', 'save', 'noise'
            ]:
                if self.plot_barriers:
                    qarglist = current_op.qargs
                    indexes = [self._get_qubit_index(x) for x in qarglist]
                    start_bit = self.qubit_list[min(indexes)]
                    if aliases is not None:
                        qarglist = map(lambda x: aliases[x], qarglist)
                    start = self.img_regs[start_bit]
                    span = len(current_op.qargs) - 1
                    for i in range(start, start + span + 1):
                        if is_occupied[i] is False:
                            is_occupied[i] = True
                        else:
                            columns += 1
                            is_occupied = [False] * self.img_width
                            for j in range(start, start + span + 1):
                                is_occupied[j] = True
                            break
                    self._latex[start][columns] = "\\qw \\barrier{" + str(
                        span) + "}"
            else:
                raise exceptions.VisualizationError("bad node data")
Esempio n. 13
0
    def _get_image_depth(self, aliases=None):
        """Get depth information for the circuit.

        Args:
            aliases (dict): dict mapping the current qubits in the circuit to
                new qubit names.

        Returns:
            int: number of columns in the circuit
            int: total size of columns in the circuit

        Raises:
            VisualizationError: if trying to draw unsupported gates
        """
        columns = 2  # wires in the beginning and end
        is_occupied = [False] * self.img_width
        max_column_width = {}
        for op in self.ops:
            # useful information for determining row spacing
            boxed_gates = [
                'u0', 'u1', 'u2', 'u3', 'x', 'y', 'z', 'h', 's', 'sdg', 't',
                'tdg', 'rx', 'ry', 'rz', 'ch', 'cy', 'crz', 'cu3', 'id'
            ]
            target_gates = ['cx', 'ccx']
            if op.name in boxed_gates:
                self.has_box = True
            if op.name in target_gates:
                self.has_target = True

            # useful information for determining column widths and final image
            # scaling
            if op.name not in ['measure', 'reset', 'barrier']:
                qarglist = op.qargs
                if aliases is not None:
                    qarglist = map(lambda x: aliases[x], qarglist)
                if len(qarglist) == 1:
                    pos_1 = self.img_regs[(qarglist[0][0], qarglist[0][1])]
                    if op.condition:
                        mask = self._get_mask(op.condition[0])
                        cl_reg = self.clbit_list[self._ffs(mask)]
                        if_reg = cl_reg[0]
                        pos_2 = self.img_regs[cl_reg]
                        for i in range(pos_1, pos_2 + self.cregs[if_reg]):
                            if is_occupied[i] is False:
                                is_occupied[i] = True
                            else:
                                columns += 1
                                is_occupied = [False] * self.img_width
                                for j in range(pos_1, pos_2 + 1):
                                    is_occupied[j] = True
                                break
                    else:
                        if is_occupied[pos_1] is False:
                            is_occupied[pos_1] = True
                        else:
                            columns += 1
                            is_occupied = [False] * self.img_width
                            is_occupied[pos_1] = True
                elif len(qarglist) == 2:
                    pos_1 = self.img_regs[(qarglist[0][0], qarglist[0][1])]
                    pos_2 = self.img_regs[(qarglist[1][0], qarglist[1][1])]

                    if op.condition:
                        mask = self._get_mask(op.condition[0])
                        cl_reg = self.clbit_list[self._ffs(mask)]
                        if_reg = cl_reg[0]
                        pos_3 = self.img_regs[(if_reg, 0)]
                        if pos_1 > pos_2:
                            for i in range(pos_2, pos_3 + self.cregs[if_reg]):
                                if is_occupied[i] is False:
                                    is_occupied[i] = True
                                else:
                                    columns += 1
                                    is_occupied = [False] * self.img_width
                                    for j in range(pos_2, pos_3 + 1):
                                        is_occupied[j] = True
                                    break
                        else:
                            for i in range(pos_1, pos_3 + self.cregs[if_reg]):
                                if is_occupied[i] is False:
                                    is_occupied[i] = True
                                else:
                                    columns += 1
                                    is_occupied = [False] * self.img_width
                                    for j in range(pos_1, pos_3 + 1):
                                        is_occupied[j] = True
                                    break
                        # symetric gates have angle labels
                        if op.name in ['cu1']:
                            columns += 1
                            is_occupied = [False] * self.img_width
                            is_occupied[max(pos_1, pos_2)] = True
                    else:
                        temp = [pos_1, pos_2]
                        temp.sort(key=int)
                        top = temp[0]
                        bottom = temp[1]

                        for i in range(top, bottom + 1):
                            if is_occupied[i] is False:
                                is_occupied[i] = True
                            else:
                                columns += 1
                                is_occupied = [False] * self.img_width
                                for j in range(top, bottom + 1):
                                    is_occupied[j] = True
                                break
                        # symetric gates have angle labels
                        if op.name in ['cu1']:
                            columns += 1
                            is_occupied = [False] * self.img_width
                            is_occupied[top] = True

                elif len(qarglist) == 3:
                    pos_1 = self.img_regs[(qarglist[0][0], qarglist[0][1])]
                    pos_2 = self.img_regs[(qarglist[1][0], qarglist[1][1])]
                    pos_3 = self.img_regs[(qarglist[2][0], qarglist[2][1])]

                    if op.condition:
                        mask = self._get_mask(op.condition[0])
                        cl_reg = self.clbit_list[self._ffs(mask)]
                        if_reg = cl_reg[0]
                        pos_4 = self.img_regs[(if_reg, 0)]

                        temp = [pos_1, pos_2, pos_3, pos_4]
                        temp.sort(key=int)
                        top = temp[0]
                        bottom = temp[2]

                        for i in range(top, pos_4 + 1):
                            if is_occupied[i] is False:
                                is_occupied[i] = True
                            else:
                                columns += 1
                                is_occupied = [False] * self.img_width
                                for j in range(top, pos_4 + 1):
                                    is_occupied[j] = True
                                break
                    else:
                        temp = [pos_1, pos_2, pos_3]
                        temp.sort(key=int)
                        top = temp[0]
                        bottom = temp[2]

                        for i in range(top, bottom + 1):
                            if is_occupied[i] is False:
                                is_occupied[i] = True
                            else:
                                columns += 1
                                is_occupied = [False] * self.img_width
                                for j in range(top, bottom + 1):
                                    is_occupied[j] = True
                                break

                # update current column width
                arg_str_len = 0
                for arg in op.op.params:
                    arg_str = re.sub(r'[-+]?\d*\.\d{2,}|\d{2,}',
                                     _truncate_float, str(arg))
                    arg_str_len += len(arg_str)
                if columns not in max_column_width:
                    max_column_width[columns] = 0
                max_column_width[columns] = max(arg_str_len,
                                                max_column_width[columns])
            elif op.name == "measure":
                if len(op.cargs) != 1 or len(op.qargs) != 1:
                    raise exceptions.VisualizationError("bad operation record")
                if op.condition:
                    raise exceptions.VisualizationError(
                        'conditional measures currently not supported.')
                qname, qindex = op.qargs[0]
                cname, cindex = op.cargs[0]
                if aliases:
                    newq = aliases[(qname, qindex)]
                    qname = newq[0]
                    qindex = newq[1]
                pos_1 = self.img_regs[(qname, qindex)]
                pos_2 = self.img_regs[(cname, cindex)]
                temp = [pos_1, pos_2]
                temp.sort(key=int)
                [pos_1, pos_2] = temp
                for i in range(pos_1, pos_2 + 1):
                    if is_occupied[i] is False:
                        is_occupied[i] = True
                    else:
                        columns += 1
                        is_occupied = [False] * self.img_width
                        for j in range(pos_1, pos_2 + 1):
                            is_occupied[j] = True
                        break
                # update current column width
                if columns not in max_column_width:
                    max_column_width[columns] = 0
            elif op.name == "reset":
                if 'conditional' in op and op.condition:
                    raise exceptions.VisualizationError(
                        'conditional reset currently not supported.')
                qname, qindex = op.qargs[0]
                if aliases:
                    newq = aliases[(qname, qindex)]
                    qname = newq[0]
                    qindex = newq[1]
                pos_1 = self.img_regs[(qname, qindex)]
                if is_occupied[pos_1] is False:
                    is_occupied[pos_1] = True
                else:
                    columns += 1
                    is_occupied = [False] * self.img_width
                    is_occupied[pos_1] = True
            elif op.name in ["barrier", 'snapshot', 'load', 'save', 'noise']:
                if self.plot_barriers:
                    qarglist = op.qargs
                    indexes = [self._get_qubit_index(x) for x in qarglist]
                    start_bit = self.qubit_list[min(indexes)]
                    if aliases is not None:
                        qarglist = map(lambda x: aliases[x], qarglist)
                    start = self.img_regs[start_bit]
                    span = len(op.qargs) - 1
                    for i in range(start, start + span + 1):
                        if is_occupied[i] is False:
                            is_occupied[i] = True
                        else:
                            columns += 1
                            is_occupied = [False] * self.img_width
                            for j in range(start, start + span + 1):
                                is_occupied[j] = True
                            break
                    # update current column width
                    if columns not in max_column_width:
                        max_column_width[columns] = 0
            else:
                raise exceptions.VisualizationError("bad node data")
        # every 3 characters is roughly one extra 'unit' of width in the cell
        # the gate name is 1 extra 'unit'
        # the qubit/cbit labels plus initial states is 2 more
        # the wires poking out at the ends is 2 more
        sum_column_widths = sum(1 + v / 3 for v in max_column_width.values())
        return columns + 1, math.ceil(sum_column_widths) + 4