def _latex_circuit_drawer(circuit,
                          scale=0.7,
                          filename=None,
                          style=None,
                          plot_barriers=True,
                          reverse_bits=False,
                          justify=None,
                          idle_wires=True,
                          with_layout=True):
    """Draw a quantum circuit based on latex (Qcircuit package)

    Requires version >=2.6.0 of the qcircuit LaTeX package.

    Args:
        circuit (QuantumCircuit): a quantum circuit
        scale (float): scaling factor
        filename (str): file path to save image to
        style (dict or str): dictionary of style or file name of style file
        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 (str) : `left`, `right` or `none`. Defaults to `left`. Says how
                        the circuit should be justified.
        idle_wires (bool): Include idle wires. Default is True.
        with_layout (bool): Include layout information, with labels on the physical
            layout. Default: True
    Returns:
        PIL.Image: an in-memory representation of the circuit diagram

    Raises:
        OSError: usually indicates that ```pdflatex``` or ```pdftocairo``` is
                 missing.
        CalledProcessError: usually points errors during diagram creation.
        ImportError: if pillow is not installed
    """
    tmpfilename = 'circuit'
    with tempfile.TemporaryDirectory() as tmpdirname:
        tmppath = os.path.join(tmpdirname, tmpfilename + '.tex')
        _generate_latex_source(circuit,
                               filename=tmppath,
                               scale=scale,
                               style=style,
                               plot_barriers=plot_barriers,
                               reverse_bits=reverse_bits,
                               justify=justify,
                               idle_wires=idle_wires,
                               with_layout=with_layout)
        try:

            subprocess.run([
                "pdflatex", "-halt-on-error",
                "-output-directory={}".format(tmpdirname),
                "{}".format(tmpfilename + '.tex')
            ],
                           stdout=subprocess.PIPE,
                           stderr=subprocess.DEVNULL,
                           check=True)
        except OSError as ex:
            if ex.errno == errno.ENOENT:
                logger.warning('WARNING: Unable to compile latex. '
                               'Is `pdflatex` installed? '
                               'Skipping latex circuit drawing...')
            raise
        except subprocess.CalledProcessError as ex:
            with open('latex_error.log', 'wb') as error_file:
                error_file.write(ex.stdout)
            logger.warning('WARNING Unable to compile latex. '
                           'The output from the pdflatex command can '
                           'be found in latex_error.log')
            raise
        else:
            if not HAS_PIL:
                raise ImportError('The latex drawer needs pillow installed. '
                                  'Run "pip install pillow" before using the '
                                  'latex drawer.')
            try:
                base = os.path.join(tmpdirname, tmpfilename)
                subprocess.run([
                    "pdftocairo", "-singlefile", "-png", "-q", base + '.pdf',
                    base
                ])
                image = Image.open(base + '.png')
                image = utils._trim(image)
                os.remove(base + '.png')
                if filename:
                    image.save(filename, 'PNG')
            except OSError as ex:
                if ex.errno == errno.ENOENT:
                    logger.warning('WARNING: Unable to convert pdf to image. '
                                   'Is `poppler` installed? '
                                   'Skipping circuit drawing...')
                raise
        return image
Esempio n. 2
0
def _latex_circuit_drawer(
    circuit,
    scale=0.7,
    style=None,
    filename=None,
    plot_barriers=True,
    reverse_bits=False,
    justify=None,
    idle_wires=True,
    with_layout=True,
    initial_state=False,
    cregbundle=False,
):
    """Draw a quantum circuit based on latex (Qcircuit package)

    Requires version >=2.6.0 of the qcircuit LaTeX package.

    Args:
        circuit (QuantumCircuit): a quantum circuit
        scale (float): scaling factor
        style (dict or str): dictionary of style or file name of style file
        filename (str): file path to save image to
        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 (str) : `left`, `right` or `none`. Defaults to `left`. Says how
            the circuit should be justified.
        idle_wires (bool): Include idle wires. Default is True.
        with_layout (bool): Include layout information, with labels on the physical
            layout. Default: True
        initial_state (bool): Optional. Adds |0> in the beginning of the line.
            Default: `False`.
        cregbundle (bool): Optional. If set True, bundle classical registers.
            Default: ``False``.

    Returns:
        PIL.Image: an in-memory representation of the circuit diagram

    Raises:
        OSError: usually indicates that ```pdflatex``` or ```pdftocairo``` is
                 missing.
        CalledProcessError: usually points to errors during diagram creation.
        MissingOptionalLibraryError: if pillow is not installed
    """
    tmpfilename = "circuit"
    with tempfile.TemporaryDirectory() as tmpdirname:
        tmppath = os.path.join(tmpdirname, tmpfilename + ".tex")
        _generate_latex_source(
            circuit,
            filename=tmppath,
            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,
        )
        try:

            subprocess.run(
                [
                    "pdflatex",
                    "-halt-on-error",
                    f"-output-directory={tmpdirname}",
                    f"{tmpfilename + '.tex'}",
                ],
                stdout=subprocess.PIPE,
                stderr=subprocess.DEVNULL,
                check=True,
            )
        except OSError as ex:
            if ex.errno == errno.ENOENT:
                logger.warning(
                    "WARNING: Unable to compile latex. "
                    "Is `pdflatex` installed? "
                    "Skipping latex circuit drawing..."
                )
            raise
        except subprocess.CalledProcessError as ex:
            with open("latex_error.log", "wb") as error_file:
                error_file.write(ex.stdout)
            logger.warning(
                "WARNING Unable to compile latex. "
                "The output from the pdflatex command can "
                "be found in latex_error.log"
            )
            raise
        else:
            if not HAS_PIL:
                raise MissingOptionalLibraryError(
                    libname="pillow",
                    name="latex drawer",
                    pip_install="pip install pillow",
                )
            try:
                base = os.path.join(tmpdirname, tmpfilename)
                subprocess.run(
                    ["pdftocairo", "-singlefile", "-png", "-q", base + ".pdf", base], check=True
                )
                image = Image.open(base + ".png")
                image = utils._trim(image)
                os.remove(base + ".png")
                if filename:
                    if filename.endswith(".pdf"):
                        os.rename(base + ".pdf", filename)
                    else:
                        image.save(filename, "PNG")
            except (OSError, subprocess.CalledProcessError) as ex:
                logger.warning(
                    "WARNING: Unable to convert pdf to image. "
                    "Is `poppler` installed? "
                    "Skipping circuit drawing..."
                )
                raise
        return image
def pass_manager_drawer(pass_manager, filename, style=None, raw=False):
    """
    Draws the pass manager.

    This function needs `pydot <https://github.com/erocarrera/pydot>`, which in turn needs
    Graphviz <https://www.graphviz.org/>` to be installed.

    Args:
        pass_manager (PassManager): the pass manager to be drawn
        filename (str): file path to save image to
        style (dict or OrderedDict): keys are the pass classes and the values are
            the colors to make them. An example can be seen in the DEFAULT_STYLE. An ordered
            dict can be used to ensure a priority coloring when pass falls into multiple
            categories. Any values not included in the provided dict will be filled in from
            the default dict
        raw (Bool) : True if you want to save the raw Dot output not an image. The
            default is False.
    Returns:
        PIL.Image or None: an in-memory representation of the pass manager. Or None if
                           no image was generated or PIL is not installed.
    Raises:
        ImportError: when nxpd or pydot not installed.
        VisualizationError: If raw=True and filename=None.

    Example:
        .. code-block::

             %matplotlib inline
            from qiskit import QuantumCircuit
            from qiskit.compiler import transpile
            from qiskit.transpiler import PassManager
            from qiskit.visualization import pass_manager_drawer
            from qiskit.transpiler.passes import Unroller

            circ = QuantumCircuit(3)
            circ.ccx(0, 1, 2)
            circ.draw()

            pass_ = Unroller(['u1', 'u2', 'u3', 'cx'])
            pm = PassManager(pass_)
            new_circ = pm.run(circ)
            new_circ.draw(output='mpl')

            pass_manager_drawer(pm, "passmanager.jpg")
    """

    try:
        import subprocess

        _PROC = subprocess.Popen(['dot', '-V'],  # pylint: disable=invalid-name
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE)
        _PROC.communicate()
        if _PROC.returncode != 0:
            has_graphviz = False
        else:
            has_graphviz = True
    except Exception:  # pylint: disable=broad-except
        # this is raised when the dot command cannot be found, which means GraphViz
        # isn't installed
        has_graphviz = False

    HAS_GRAPHVIZ = has_graphviz  # pylint: disable=invalid-name

    try:
        import pydot
        if not HAS_GRAPHVIZ:
            raise ImportError
    except ImportError:
        raise ImportError("pass_manager_drawer requires pydot and graphviz. "
                          "Run 'pip install pydot'. "
                          "Graphviz can be installed using 'brew install graphviz' on Mac"
                          " or by downloading it from the website.")

    passes = pass_manager.passes()

    if not style:
        style = DEFAULT_STYLE

    # create the overall graph
    graph = pydot.Dot()

    # identifiers for nodes need to be unique, so assign an id
    # can't just use python's id in case the exact same pass was
    # appended more than once
    component_id = 0

    prev_node = None

    for index, controller_group in enumerate(passes):

        # label is the name of the flow controller parameter
        label = "[%s] %s" % (index, ', '.join(controller_group['flow_controllers']))

        # create the subgraph for this controller
        subgraph = pydot.Cluster(str(component_id), label=label, fontname='helvetica',
                                 labeljust='l')
        component_id += 1

        for pass_ in controller_group['passes']:

            # label is the name of the pass
            node = pydot.Node(str(component_id),
                              label=str(type(pass_).__name__),
                              color=_get_node_color(pass_, style),
                              shape="rectangle",
                              fontname='helvetica')

            subgraph.add_node(node)
            component_id += 1

            # the arguments that were provided to the pass when it was created
            arg_spec = inspect.getfullargspec(pass_.__init__)
            # 0 is the args, 1: to remove the self arg
            args = arg_spec[0][1:]

            num_optional = len(arg_spec[3]) if arg_spec[3] else 0

            # add in the inputs to the pass
            for arg_index, arg in enumerate(args):
                nd_style = 'solid'
                # any optional args are dashed
                # the num of optional counts from the end towards the start of the list
                if arg_index >= (len(args) - num_optional):
                    nd_style = 'dashed'

                input_node = pydot.Node(component_id, label=arg,
                                        color="black",
                                        shape="ellipse",
                                        fontsize=10,
                                        style=nd_style,
                                        fontname='helvetica')
                subgraph.add_node(input_node)
                component_id += 1
                subgraph.add_edge(pydot.Edge(input_node, node))

            # if there is a previous node, add an edge between them
            if prev_node:
                subgraph.add_edge(pydot.Edge(prev_node, node))

            prev_node = node

        graph.add_subgraph(subgraph)

    if raw:
        if filename:
            graph.write(filename, format='raw')
            return None
        else:
            raise VisualizationError("if format=raw, then a filename is required.")

    if not HAS_PIL and filename:
        # linter says this isn't a method - it is
        graph.write_png(filename)  # pylint: disable=no-member
        return None

    with tempfile.TemporaryDirectory() as tmpdirname:
        tmppath = os.path.join(tmpdirname, 'pass_manager.png')

        # linter says this isn't a method - it is
        graph.write_png(tmppath)  # pylint: disable=no-member

        image = Image.open(tmppath)
        image = utils._trim(image)
        os.remove(tmppath)
        if filename:
            image.save(filename, 'PNG')
        return image
def pass_manager_drawer(pass_manager, filename=None, style=None, raw=False):
    """
    Draws the pass manager.

    This function needs `pydot <https://github.com/erocarrera/pydot>`, which in turn needs
    Graphviz <https://www.graphviz.org/>` to be installed.

    Args:
        pass_manager (PassManager): the pass manager to be drawn
        filename (str): file path to save image to
        style (dict or OrderedDict): keys are the pass classes and the values are
            the colors to make them. An example can be seen in the DEFAULT_STYLE. An ordered
            dict can be used to ensure a priority coloring when pass falls into multiple
            categories. Any values not included in the provided dict will be filled in from
            the default dict
        raw (Bool) : True if you want to save the raw Dot output not an image. The
            default is False.
    Returns:
        PIL.Image or None: an in-memory representation of the pass manager. Or None if
        no image was generated or PIL is not installed.
    Raises:
        MissingOptionalLibraryError: when nxpd or pydot not installed.
        VisualizationError: If raw=True and filename=None.

    Example:
        .. code-block::

             %matplotlib inline
            from qiskit import QuantumCircuit
            from qiskit.compiler import transpile
            from qiskit.transpiler import PassManager
            from qiskit.visualization import pass_manager_drawer
            from qiskit.transpiler.passes import Unroller

            circ = QuantumCircuit(3)
            circ.ccx(0, 1, 2)
            circ.draw()

            pass_ = Unroller(['u1', 'u2', 'u3', 'cx'])
            pm = PassManager(pass_)
            new_circ = pm.run(circ)
            new_circ.draw(output='mpl')

            pass_manager_drawer(pm, "passmanager.jpg")
    """
    import pydot

    passes = pass_manager.passes()

    if not style:
        style = DEFAULT_STYLE

    # create the overall graph
    graph = pydot.Dot()

    # identifiers for nodes need to be unique, so assign an id
    # can't just use python's id in case the exact same pass was
    # appended more than once
    component_id = 0

    prev_node = None

    for index, controller_group in enumerate(passes):

        # label is the name of the flow controller parameter
        label = "[{}] {}".format(
            index, ", ".join(controller_group["flow_controllers"]))

        # create the subgraph for this controller
        subgraph = pydot.Cluster(str(component_id),
                                 label=label,
                                 fontname="helvetica",
                                 labeljust="l")
        component_id += 1

        for pass_ in controller_group["passes"]:

            # label is the name of the pass
            node = pydot.Node(
                str(component_id),
                label=str(type(pass_).__name__),
                color=_get_node_color(pass_, style),
                shape="rectangle",
                fontname="helvetica",
            )

            subgraph.add_node(node)
            component_id += 1

            # the arguments that were provided to the pass when it was created
            arg_spec = inspect.getfullargspec(pass_.__init__)
            # 0 is the args, 1: to remove the self arg
            args = arg_spec[0][1:]

            num_optional = len(arg_spec[3]) if arg_spec[3] else 0

            # add in the inputs to the pass
            for arg_index, arg in enumerate(args):
                nd_style = "solid"
                # any optional args are dashed
                # the num of optional counts from the end towards the start of the list
                if arg_index >= (len(args) - num_optional):
                    nd_style = "dashed"

                input_node = pydot.Node(
                    component_id,
                    label=arg,
                    color="black",
                    shape="ellipse",
                    fontsize=10,
                    style=nd_style,
                    fontname="helvetica",
                )
                subgraph.add_node(input_node)
                component_id += 1
                subgraph.add_edge(pydot.Edge(input_node, node))

            # if there is a previous node, add an edge between them
            if prev_node:
                subgraph.add_edge(pydot.Edge(prev_node, node))

            prev_node = node

        graph.add_subgraph(subgraph)

    if raw:
        if filename:
            graph.write(filename, format="raw")
            return None
        else:
            raise VisualizationError(
                "if format=raw, then a filename is required.")

    if not _optionals.HAS_PIL and filename:
        # pylint says this isn't a method - it is
        graph.write_png(filename)  # pylint: disable=no-member
        return None

    _optionals.HAS_PIL.require_now("pass manager drawer")

    with tempfile.TemporaryDirectory() as tmpdirname:
        from PIL import Image

        tmppath = os.path.join(tmpdirname, "pass_manager.png")

        # pylint says this isn't a method - it is
        graph.write_png(tmppath)  # pylint: disable=no-member

        image = Image.open(tmppath)
        image = utils._trim(image)
        os.remove(tmppath)
        if filename:
            image.save(filename, "PNG")
        return image
Esempio n. 5
0
def _latex_circuit_drawer(
    circuit,
    scale=0.7,
    style=None,
    filename=None,
    plot_barriers=True,
    reverse_bits=False,
    justify=None,
    idle_wires=True,
    with_layout=True,
    initial_state=False,
    cregbundle=False,
):
    """Draw a quantum circuit based on latex (Qcircuit package)

    Requires version >=2.6.0 of the qcircuit LaTeX package.

    Args:
        circuit (QuantumCircuit): a quantum circuit
        scale (float): scaling factor
        style (dict or str): dictionary of style or file name of style file
        filename (str): file path to save image to
        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 (str) : `left`, `right` or `none`. Defaults to `left`. Says how
            the circuit should be justified.
        idle_wires (bool): Include idle wires. Default is True.
        with_layout (bool): Include layout information, with labels on the physical
            layout. Default: True
        initial_state (bool): Optional. Adds |0> in the beginning of the line.
            Default: `False`.
        cregbundle (bool): Optional. If set True, bundle classical registers.
            Default: ``False``.

    Returns:
        PIL.Image: an in-memory representation of the circuit diagram

    Raises:
        MissingOptionalLibraryError: if pillow, pdflatex, or poppler are not installed
        VisualizationError: if one of the conversion utilities failed for some internal or
            file-access reason.
    """
    tmpfilename = "circuit"
    with tempfile.TemporaryDirectory() as tmpdirname:
        tmppath = os.path.join(tmpdirname, tmpfilename + ".tex")
        _generate_latex_source(
            circuit,
            filename=tmppath,
            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,
        )
        if not HAS_PDFLATEX:
            raise MissingOptionalLibraryError(
                libname="pdflatex",
                name="LaTeX circuit drawing",
                msg=
                "You will likely need to install a full LaTeX distribution for your system",
            )
        if not HAS_PDFTOCAIRO:
            raise MissingOptionalLibraryError(
                libname="pdftocairo",
                name="LaTeX circuit drawing",
                msg="This is part of the 'poppler' set of PDF utilities",
            )
        if not HAS_PIL:
            raise MissingOptionalLibraryError(
                libname="pillow",
                name="LaTeX circuit drawing",
                pip_install="pip install pillow",
            )
        try:
            subprocess.run(
                [
                    "pdflatex",
                    "-halt-on-error",
                    f"-output-directory={tmpdirname}",
                    f"{tmpfilename + '.tex'}",
                ],
                stdout=subprocess.PIPE,
                stderr=subprocess.DEVNULL,
                check=True,
            )
        except OSError as exc:
            # OSError should generally not occur, because it's usually only triggered if `pdflatex`
            # doesn't exist as a command, but we've already checked that.
            raise VisualizationError(
                "`pdflatex` command could not be run.") from exc
        except subprocess.CalledProcessError as exc:
            with open("latex_error.log", "wb") as error_file:
                error_file.write(exc.stdout)
            logger.warning(
                "Unable to compile LaTeX. Perhaps you are missing the `qcircuit` package."
                " The output from the `pdflatex` command is in `latex_error.log`."
            )
            raise VisualizationError(
                "`pdflatex` call did not succeed: see `latex_error.log`."
            ) from exc
        base = os.path.join(tmpdirname, tmpfilename)
        try:
            subprocess.run(
                [
                    "pdftocairo", "-singlefile", "-png", "-q", base + ".pdf",
                    base
                ],
                check=True,
            )
        except (OSError, subprocess.CalledProcessError) as exc:
            message = "`pdftocairo` failed to produce an image."
            logger.warning(message)
            raise VisualizationError(message) from exc
        image = Image.open(base + ".png")
        image = utils._trim(image)
        if filename:
            if filename.endswith(".pdf"):
                os.rename(base + ".pdf", filename)
            else:
                try:
                    image.save(filename)
                except (ValueError, OSError) as exc:
                    raise VisualizationError(
                        f"Pillow could not write the image file '{filename}'."
                    ) from exc
        return image
def pass_manager_drawer(pass_manager, filename, style=None, raw=False):
    """
    Draws the pass manager.

    This function needs `pydot <https://github.com/erocarrera/pydot>`, which in turn needs
    Graphviz <https://www.graphviz.org/>` to be installed.

    Args:
        pass_manager (PassManager): the pass manager to be drawn
        filename (str): file path to save image to
        style (dict or OrderedDict): keys are the pass classes and the values are
            the colors to make them. An example can be seen in the DEFAULT_STYLE. An ordered
            dict can be used to ensure a priority coloring when pass falls into multiple
            categories. Any values not included in the provided dict will be filled in from
            the default dict
        raw (Bool) : True if you want to save the raw Dot output not an image. The
            default is False.
    Returns:
        PIL.Image or None: an in-memory representation of the pass manager. Or None if
                           no image was generated or PIL is not installed.
    Raises:
        ImportError: when nxpd or pydot not installed.
    """

    try:
        import pydot
        if not HAS_GRAPHVIZ:
            raise ImportError
    except ImportError:
        raise ImportError(
            "pass_manager_drawer requires pydot and graphviz. "
            "Run 'pip install pydot'. "
            "Graphviz can be installed using 'brew install graphviz' on Mac"
            " or by downloading it from the website.")

    passes = pass_manager.passes()

    if not style:
        style = DEFAULT_STYLE

    # create the overall graph
    graph = pydot.Dot()

    # identifiers for nodes need to be unique, so assign an id
    # can't just use python's id in case the exact same pass was
    # appended more than once
    component_id = 0

    prev_node = None

    for controller_group in passes:

        # label is the name of the flow controller (without the word controller)
        label = controller_group['type'].__name__.replace('Controller', '')

        # create the subgraph for this controller
        subgraph = pydot.Cluster(str(component_id),
                                 label=label,
                                 fontname='helvetica')
        component_id += 1

        for pass_ in controller_group['passes']:

            # label is the name of the pass
            node = pydot.Node(str(component_id),
                              label=str(type(pass_).__name__),
                              color=_get_node_color(pass_, style),
                              shape="rectangle",
                              fontname='helvetica')

            subgraph.add_node(node)
            component_id += 1

            # the arguments that were provided to the pass when it was created
            arg_spec = inspect.getfullargspec(pass_.__init__)
            # 0 is the args, 1: to remove the self arg
            args = arg_spec[0][1:]

            num_optional = len(arg_spec[3]) if arg_spec[3] else 0

            # add in the inputs to the pass
            for arg_index, arg in enumerate(args):
                nd_style = 'solid'
                # any optional args are dashed
                # the num of optional counts from the end towards the start of the list
                if arg_index >= (len(args) - num_optional):
                    nd_style = 'dashed'

                input_node = pydot.Node(component_id,
                                        label=arg,
                                        color="black",
                                        shape="ellipse",
                                        fontsize=10,
                                        style=nd_style,
                                        fontname='helvetica')
                subgraph.add_node(input_node)
                component_id += 1
                subgraph.add_edge(pydot.Edge(input_node, node))

            # if there is a previous node, add an edge between them
            if prev_node:
                subgraph.add_edge(pydot.Edge(prev_node, node))

            prev_node = node

        graph.add_subgraph(subgraph)

    if raw and filename:
        graph.write(filename, format='raw')

    if not HAS_PIL and filename:
        # linter says this isn't a method - it is
        graph.write_png(filename)  # pylint: disable=no-member
        return None

    with tempfile.TemporaryDirectory() as tmpdirname:
        tmppath = os.path.join(tmpdirname, 'pass_manager.png')

        # linter says this isn't a method - it is
        graph.write_png(tmppath)  # pylint: disable=no-member

        image = Image.open(tmppath)
        image = utils._trim(image)
        os.remove(tmppath)
        if filename:
            image.save(filename, 'PNG')
        return image