# # Copyright 2021 Quantum Benchmark Inc. # """ External Interfaces: Introduction ================================= """ #%% # In this example, we demonstrate how to convert between the |True-Q| python circuit # representation and other popular third party representations. These conversions # will only be available if the corresponding python packages are installed. # # We start by defining a test circuit to work with: import trueq as tq circuit = tq.Circuit( [ {(0,): tq.Gate.x, (1,): tq.Gate.y}, {(0, 2): tq.Gate.cz, (1,): tq.Gate.x}, {(3,): tq.Gate.h, (5,): tq.Gate.s}, ] ) circuit.measure_all() #%% # Cirq # ---- # Convert the circuit to a Cirq circuit object: cirq_circuit = circuit.to_cirq() cirq_circuit #%% # Perform the inverse conversion (to_trueq() is monkey-patched onto their circuit object # at |True-Q| import time): cirq_circuit.to_trueq() #%% # PyQuil # ------ # Convert the circuit to a PyQuil circuit object: pyquil_circuit = circuit.to_pyquil() print(pyquil_circuit) #%% # Perform the inverse conversion (to_trueq() is monkey-patched onto their circuit object # at |True-Q| import time): pyquil_circuit.to_trueq() #%% # Qiskit # ------ # Set the preferred gates to build into (See below for more details), then convert the # circuit to a Qiskit circuit object: tq.interface.qiskit.set_config(["CXGate", "UGate"]) qiskit_circuit = circuit.to_qiskit() qiskit_circuit.draw("mpl") #%% # Perform the inverse conversion (to_trueq() is monkey-patched onto their circuit object # at |True-Q| import time): qiskit_circuit.to_trueq() #%% # 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`.