# # Copyright 2022 Keysight Technologies Inc. # """ Interfacing with Other Software =============================== """ #%% # You can use the unique functionality of |True-Q| for projects developed in other # quantum computing software libraries by converting objects created by those projects # to |True-Q|. You can also use functionality from other quantum computing software # libraries by converting |True-Q| objects into their format. |True-Q| can natively # convert to and from: #%% # #. QASM # A quantum assembly language used by many quantum hardware makers. # #. Qiskit # IBM's quantum computing software package. # #. Cirq # Google's quantum computing software package. # #. PyQuil # Rigetti's quantum computing software package. #%% # Before converting a circuit to/from a software package, the first thing to consider is # what gates you want the outputted circuit to use---since each software package is # independently written, the primitive gates they each use may differ. By default, # |True-Q| will recompile using only the gates supported by the software package. # However, more advanced users can specify a subset of supported gates to compile into # when converting between software platforms (see :doc:`interface_software`\). #%% # .. note:: Before starting, make sure that you have installed the software that you # want to convert from, by trying to import it into your Python notebook. If they are # successfully installed, continue on to the next section. |True-Q| does not # automatically install the third-party libraries from above, so if you want to use # them you need to install them separately. #%% # Examples of Back and Forth Conversions # -------------------------------------- # To get a feel for converting between |True-Q| and other software packages, we will # show an example converting from |True-Q| to Cirq and back. Try constructing a circuit # in |True-Q| then running :py:func:`~trueq.Circuit.to_cirq`\, like this: import trueq as tq circuit = tq.Circuit({(0, 1): tq.Gate.cz}) circuit.draw(interactive=False) cirq_circuit = circuit.to_cirq() cirq_circuit #%% # Notice that the ``cirq_circuit`` object is a Cirq circuit, so the output for that # object is drawn using Cirq's visualization tools. If we want to convert back to # |True-Q|, we can use the following code and use :py:meth:`~trueq.Circuit.draw` to draw # a circuit diagram. circ = cirq_circuit.to_trueq() circ.draw(interactive=False) #%% # In this case, we get back the same circuit that we initially converted to a Cirq # object. #%% # If we use a gate that is not directly available in Cirq in our circuit, the conversion # will look a little different. For example, ``tq.Gate.cy`` is not supported by Cirq. # Here's what happens when we run the same steps as above for ``tq.Gate.cy``: # construct and draw a TrueQ circuit circuit = tq.Circuit({(0, 1): tq.Gate.cy}) circuit.draw(interactive=False) # convert to Cirq and draw cirq_circuit = circuit.to_cirq() cirq_circuit # convert back to TrueQ and draw circ = cirq_circuit.to_trueq() circ.draw(interactive=False) #%% # Notice that |True-Q|'s compilation tools automatically rewrote the circuit in order to # reflect the input accurately when converting to a different software platform. When we # convert back, the circuit does not automatically get simplified back to its original # form because |True-Q| supports any gate. This is where configuration files (see # :doc:`../../guides/compilation/configuration`) come in handy; had we carefully # specified which gates we wanted the final |True-Q| circuit to use, we could have ended # with the original |True-Q| circuit. #%% # For this example, we used the interface with Cirq, but we might also have used the # analogous methods :py:func:`~trueq.Circuit.to_qiskit` and # :py:func:`~trueq.Circuit.to_pyquil` to convert to and from Qiskit and PyQuil. Try # these methods out and see if you can find examples of gates that are and are not # supported by these other platforms. #%% # Interface Config # ---------------- # During conversion between representations in |True-Q| and other software packages, # there is often a degeneracy in how a gate may be converted. For example, an identity # gate could be written as ``Z(phi)``, ``X(phi)``, ``Y(phi)``, ... with ``phi = 0``. # # In these cases, this degeneracy can be broken by setting the preferred order of gate # conversion. This is done in the interfaces through a :py:class:`~trueq.Config` which # contains a collection of :py:class:`~trueq.config.GateFactory`\s. Each of these # factories has the exact name and parameters of the corresponding gate representation # in the external software. During the conversion of any specific gate from |True-Q| # into the external software, each of these factories is used in order until the # conversion is possible. # # The default settings for all interfaces is to have the defined config contain all # possible gates allowed in the external software, even though there are typically # degeneracies. This default configuration is available through the # :py:meth:`~trueq.interface.base.Interface.default_config` method on every interface. # # The current active config may be changed through the respective # :py:meth:`~trueq.interface.base.Interface.set_config` and # :py:meth:`~trueq.interface.base.Interface.get_config` which are also available on # every interface. #%% # Look at the config list for the interface between |True-Q| and Cirq: std_config = tq.interface.cirq.default_config() #%% # Set a reduced config, containing only ``CNOT``, ``XPowGate``, and ``ZPowGate``: tq.interface.cirq.set_config(["CNOT", "XPowGate", "ZPowGate"]) #%% # This may have also been set through a subset of the default config: tq.interface.cirq.set_config(std_config.subset(names=["CNOT", "XPowGate", "ZPowGate"])) #%% # Convert the circuit defined above to Cirq using the updated config: circuit.to_cirq() #%% # .. note :: # Setting the config to ``None`` resets to the default config. #%% # Reset the config to the default: tq.interface.cirq.set_config(None) #%% # Convert the circuit to Cirq using the default config circuit.to_cirq() #%% # As you can see in the printed circuits, changing the config alters the gates used in # converting from |True-Q| to other software. For example, removing the ``X`` gate from # the config causes the interface to pick the next viable representation of this # operation, so that the ``X`` gates are given as rotations about ``X`` by :math:`\pi`\.