{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "%matplotlib inline" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n# Interfacing with Other Software\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can use the unique functionality of |True-Q| for projects developed in other\nquantum computing software libraries by converting objects created by those projects\nto |True-Q|. You can also use functionality from other quantum computing software\nlibraries by converting |True-Q| objects into their format. |True-Q| can natively\nconvert to and from:\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#. QASM\n A quantum assembly language used by many quantum hardware makers.\n#. Qiskit\n IBM's quantum computing software package.\n#. Cirq\n Google's quantum computing software package.\n#. PyQuil\n Rigetti's quantum computing software package.\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Before converting a circuit to/from a software package, the first thing to consider is\nwhat gates you want the outputted circuit to use---since each software package is\nindependently written, the primitive gates they each use may differ. By default,\n|True-Q| will recompile using only the gates supported by the software package.\nHowever, more advanced users can specify a subset of supported gates to compile into\nwhen converting between software platforms (see :doc:`interface_software`\\).\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Note

Before starting, make sure that you have installed the software that you\n want to convert from, by trying to import it into your Python notebook. If they are\n successfully installed, continue on to the next section. |True-Q| does not\n automatically install the third-party libraries from above, so if you want to use\n them you need to install them separately.

\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Examples of Back and Forth Conversions\nTo get a feel for converting between |True-Q| and other software packages, we will\nshow an example converting from |True-Q| to Cirq and back. Try constructing a circuit\nin |True-Q| then running :py:func:`~trueq.Circuit.to_cirq`\\, like this:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import trueq as tq\n\ncircuit = tq.Circuit({(0, 1): tq.Gate.cz})\ncircuit.draw(interactive=False)\n\ncirq_circuit = circuit.to_cirq()\ncirq_circuit" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice that the ``cirq_circuit`` object is a Cirq circuit, so the output for that\nobject is drawn using Cirq's visualization tools. If we want to convert back to\n|True-Q|, we can use the following code and use :py:meth:`~trueq.Circuit.draw` to draw\na circuit diagram.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "circ = cirq_circuit.to_trueq()\ncirc.draw(interactive=False)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this case, we get back the same circuit that we initially converted to a Cirq\nobject.\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we use a gate that is not directly available in Cirq in our circuit, the conversion\nwill look a little different. For example, ``tq.Gate.cy`` is not supported by Cirq.\nHere's what happens when we run the same steps as above for ``tq.Gate.cy``:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# construct and draw a TrueQ circuit\ncircuit = tq.Circuit({(0, 1): tq.Gate.cy})\ncircuit.draw(interactive=False)\n\n# convert to Cirq and draw\ncirq_circuit = circuit.to_cirq()\ncirq_circuit\n\n# convert back to TrueQ and draw\ncirc = cirq_circuit.to_trueq()\ncirc.draw(interactive=False)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice that |True-Q|'s compilation tools automatically rewrote the circuit in order to\nreflect the input accurately when converting to a different software platform. When we\nconvert back, the circuit does not automatically get simplified back to its original\nform because |True-Q| supports any gate. This is where configuration files (see\n:doc:`../../guides/compilation/configuration`) come in handy; had we carefully\nspecified which gates we wanted the final |True-Q| circuit to use, we could have ended\nwith the original |True-Q| circuit.\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For this example, we used the interface with Cirq, but we might also have used the\nanalogous methods :py:func:`~trueq.Circuit.to_qiskit` and\n:py:func:`~trueq.Circuit.to_pyquil` to convert to and from Qiskit and PyQuil. Try\nthese methods out and see if you can find examples of gates that are and are not\nsupported by these other platforms.\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Interface Config\nDuring conversion between representations in |True-Q| and other software packages,\nthere is often a degeneracy in how a gate may be converted. For example, an identity\ngate could be written as ``Z(phi)``, ``X(phi)``, ``Y(phi)``, ... with ``phi = 0``.\n\nIn these cases, this degeneracy can be broken by setting the preferred order of gate\nconversion. This is done in the interfaces through a :py:class:`~trueq.Config` which\ncontains a collection of :py:class:`~trueq.config.GateFactory`\\s. Each of these\nfactories has the exact name and parameters of the corresponding gate representation\nin the external software. During the conversion of any specific gate from |True-Q|\ninto the external software, each of these factories is used in order until the\nconversion is possible.\n\nThe default settings for all interfaces is to have the defined config contain all\npossible gates allowed in the external software, even though there are typically\ndegeneracies. This default configuration is available through the\n:py:meth:`~trueq.interface.base.Interface.default_config` method on every interface.\n\nThe current active config may be changed through the respective\n:py:meth:`~trueq.interface.base.Interface.set_config` and\n:py:meth:`~trueq.interface.base.Interface.get_config` which are also available on\nevery interface.\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Look at the config list for the interface between |True-Q| and Cirq:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "std_config = tq.interface.cirq.default_config()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Set a reduced config, containing only ``CNOT``, ``XPowGate``, and ``ZPowGate``:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "tq.interface.cirq.set_config([\"CNOT\", \"XPowGate\", \"ZPowGate\"])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This may have also been set through a subset of the default config:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "tq.interface.cirq.set_config(std_config.subset(names=[\"CNOT\", \"XPowGate\", \"ZPowGate\"]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Convert the circuit defined above to Cirq using the updated config:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "circuit.to_cirq()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ ".. note ::\n Setting the config to ``None`` resets to the default config.\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Reset the config to the default:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "tq.interface.cirq.set_config(None)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Convert the circuit to Cirq using the default config\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "circuit.to_cirq()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As you can see in the printed circuits, changing the config alters the gates used in\nconverting from |True-Q| to other software. For example, removing the ``X`` gate from\nthe config causes the interface to pick the next viable representation of this\noperation, so that the ``X`` gates are given as rotations about ``X`` by $\\pi$\\.\n\n" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.12" } }, "nbformat": 4, "nbformat_minor": 0 }