From c6e294675ad0ea6f805532672e2b2d01fa11ca58 Mon Sep 17 00:00:00 2001 From: Alessandro Candido Date: Tue, 16 Jan 2024 17:18:12 +0100 Subject: [PATCH 1/2] Remove transpiler related tutorial --- doc/source/tutorials/index.rst | 1 - doc/source/tutorials/transpiler.rst | 163 ---------------------------- 2 files changed, 164 deletions(-) delete mode 100644 doc/source/tutorials/transpiler.rst diff --git a/doc/source/tutorials/index.rst b/doc/source/tutorials/index.rst index 32e71237c..c3e11046d 100644 --- a/doc/source/tutorials/index.rst +++ b/doc/source/tutorials/index.rst @@ -12,5 +12,4 @@ In this section we present code examples from basic to advanced features impleme pulses circuits calibration - transpiler instrument diff --git a/doc/source/tutorials/transpiler.rst b/doc/source/tutorials/transpiler.rst deleted file mode 100644 index 5b06086dd..000000000 --- a/doc/source/tutorials/transpiler.rst +++ /dev/null @@ -1,163 +0,0 @@ -.. _tutorials_transpiler: - -How to modify the transpiler? -============================= - -A Qibolab platform can execute pulse sequences. -As shown in :ref:`tutorials_circuits`, Qibo circuits can be executed by invoking the :class:`qibolab.backends.QibolabBackend`, which is the object integrating Qibolab to Qibo. -When a Qibo circuit is executed, the backend will automatically transpile and compile it to a pulse sequence, which will be sent to the platform for execution. -The default transpilers and compiler outlined in the :ref:`main_doc_transpiler` section will be used in this process. -In this tutorial we will demonstrate how the user can modify this process for custom applications. - -The ``transpiler`` and ``compiler`` objects used when executing a circuit are attributes of :class:`qibolab.backends.QibolabBackend`. -Creating an instance of the backend provides access to these objects: - -.. testcode:: python - - from qibolab.backends import QibolabBackend - - backend = QibolabBackend(platform="dummy") - - print(type(backend.transpiler)) - print(type(backend.compiler)) - -.. testoutput:: python - :hide: - - - - -The transpiler is responsible for transforming the circuit to respect the chip connectivity and native gates, -while the compiler transforms the circuit to the equivalent pulse sequence. -The user can modify these attributes before executing a circuit. -For example: - -.. testcode:: python - - from qibo import gates - from qibo.models import Circuit - from qibolab.backends import QibolabBackend - - # define circuit - circuit = Circuit(1) - circuit.add(gates.U3(0, 0.1, 0.2, 0.3)) - circuit.add(gates.M(0)) - - backend = QibolabBackend(platform="dummy") - # disable the transpiler - backend.transpiler = None - - # execute circuit - result = backend.execute_circuit(circuit, nshots=1000) - -completely disables the transpilation steps. In this case the circuit will be sent directly to the compiler, to be compiled to a pulse sequence. -Instead of completely disabling, custom transpilation steps can be given: - -.. testcode:: python - - from qibolab.backends import QibolabBackend - - from qibo.transpiler.unroller import NativeGates, Unroller - - backend = QibolabBackend(platform="dummy") - backend.transpiler = Unroller(native_gates=NativeGates.CZ) - - -Now circuits will only be transpiled to native gates, without any connectivity matching steps. -The transpiler used in this example assumes Z, RZ, GPI2 or U3 as the single-qubit native gates, and supports CZ and iSWAP as two-qubit natives. -In this case we restricted the two-qubit gate set to CZ only. -If the circuit to be executed contains gates that are not included in this gate set, they will be transformed to multiple gates from the gate set. -Arbitrary single-qubit gates are typically transformed to U3. -Arbitrary two-qubit gates are transformed to two or three CZ gates following their `universal CNOT decomposition `_. -The decomposition of some common gates such as the SWAP and CNOT is hard-coded for efficiency. - -Multiple transpilation steps can be implemented using the transpiler ``Passes``: - -.. testcode:: python - - from qibo.transpiler import Passes - from qibo.transpiler.unroller import NativeGates, Unroller - from qibo.transpiler.star_connectivity import StarConnectivity - - backend = QibolabBackend(platform="dummy") - backend.transpiler = Passes( - [ - StarConnectivity(middle_qubit=2), - Unroller(native_gates=NativeGates.CZ), - ] - ) - -In this case circuits will first be transpiled to respect the 5-qubit star connectivity, with qubit 2 as the middle qubit. This will potentially add some SWAP gates. Then all gates will be converted to native. - -The compiler can be modified similarly, by adding new compilation rules or modifying existing ones. -As explained in :ref:`main_doc_transpiler` section, a rule is a function that accepts a Qibo gate and a Qibolab platform and returns the corresponding pulse sequence implementing this gate. - -The following example shows how to modify the transpiler and compiler in order to execute a circuit containing a Pauli X gate using a single pi-pulse: - -.. testcode:: python - - from qibo import gates - from qibo.models import Circuit - from qibolab.backends import QibolabBackend - from qibolab.pulses import PulseSequence - - # define the circuit - circuit = Circuit(1) - circuit.add(gates.X(0)) - circuit.add(gates.M(0)) - - - # define a compiler rule that translates X to the pi-pulse - def x_rule(gate, platform): - """X gate applied with a single pi-pulse.""" - qubit = gate.target_qubits[0] - sequence = PulseSequence() - sequence.add(platform.create_RX_pulse(qubit, start=0)) - return sequence, {} - - - # the empty dictionary is needed because the X gate does not require any virtual Z-phases - - backend = QibolabBackend(platform="dummy") - # disable the transpiler (the default transpiler will attempt to convert X to U3) - backend.transpiler = None - # register the new X rule in the compiler - backend.compiler[gates.X] = x_rule - - # execute the circuit - result = backend.execute_circuit(circuit, nshots=1000) - -Here we completely disabled the transpiler to avoid transforming the X gate to a different gate and we added a rule that instructs the compiler how to transform the X gate. - -The default set of compiler rules is defined in :py:mod:`qibolab.compilers.default`. - -.. note:: - If the compiler receives a circuit that contains a gate for which it has no rule, an error will be raised. - This means that the native gate set that the transpiler uses, should be compatible with the available compiler rules. - If the transpiler is disabled, a rule should be available for all gates in the original circuit. - -In the above examples we executed circuits using the backend ``backend.execute_circuit`` method, -unlike the previous example (:ref:`tutorials_circuits`) where circuits were executed directly using ``circuit(nshots=1000)``. -It is possible to perform transpiler and compiler manipulation in both approaches. -When using ``circuit(nshots=1000)``, Qibo is automatically initializing a ``GlobalBackend()`` singleton that is used to execute the circuit. -Therefore the previous manipulations can be done as follows: - -.. testcode:: python - - import qibo - from qibo import gates - from qibo.models import Circuit - from qibo.backends import GlobalBackend - - # define circuit - circuit = Circuit(1) - circuit.add(gates.U3(0, 0.1, 0.2, 0.3)) - circuit.add(gates.M(0)) - - # set backend to qibolab - qibo.set_backend("qibolab", platform="dummy") - # disable the transpiler - GlobalBackend().transpiler = None - - # execute circuit - result = circuit(nshots=1000) From c1596a3d7eb87e5f69b5de38a88ccec7d9b9d792 Mon Sep 17 00:00:00 2001 From: Stavros Efthymiou <35475381+stavros11@users.noreply.github.com> Date: Fri, 19 Jan 2024 22:32:02 +0400 Subject: [PATCH 2/2] Keep compiler tutorial --- doc/source/index.rst | 5 +- doc/source/main-documentation/qibolab.rst | 2 +- doc/source/tutorials/circuits.rst | 4 +- doc/source/tutorials/compiler.rst | 132 ++++++++++++++++++++++ doc/source/tutorials/index.rst | 1 + 5 files changed, 138 insertions(+), 6 deletions(-) create mode 100644 doc/source/tutorials/compiler.rst diff --git a/doc/source/index.rst b/doc/source/index.rst index 3d56ac920..9add0a628 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -15,9 +15,8 @@ circuits on quantum hardware. Qibolab includes: 1. :ref:`Platform API `: support custom allocation of quantum hardware platforms / lab setup. 2. :ref:`Drivers `: supports commercial and open-source firmware for hardware control. 3. :ref:`Arbitrary pulse API `: provide a library of custom pulses for execution through instruments. -4. :ref:`Transpiler `: compiles quantum circuits into pulse sequences matching chip topology. -5. :ref:`Quantum Circuit Deployment `: seamlessly deploys quantum circuit models on - quantum hardware. +4. :ref:`Compiler `: compiles quantum circuits into pulse sequences. +5. :ref:`Quantum Circuit Deployment `: seamlessly deploys quantum circuit models on quantum hardware. Components ---------- diff --git a/doc/source/main-documentation/qibolab.rst b/doc/source/main-documentation/qibolab.rst index ad2c467d1..e7e772b37 100644 --- a/doc/source/main-documentation/qibolab.rst +++ b/doc/source/main-documentation/qibolab.rst @@ -647,7 +647,7 @@ The shape of the values of an integreted acquisition with 2 sweepers will be: ) shape = (options.nshots, len(sweeper1.values), len(sweeper2.values)) -.. _main_doc_transpiler: +.. _main_doc_compiler: Transpiler and Compiler ----------------------- diff --git a/doc/source/tutorials/circuits.rst b/doc/source/tutorials/circuits.rst index b9a87d4f5..cea7bad28 100644 --- a/doc/source/tutorials/circuits.rst +++ b/doc/source/tutorials/circuits.rst @@ -128,8 +128,8 @@ Returns the following plot: :class: only-dark .. note:: - Executing circuits using the Qibolab backend results to automatic application of the transpilation and compilation pipelines (:ref:`main_doc_transpiler`) which convert the circuit to a pulse sequence that is executed by the given platform. - It is possible to modify these pipelines following the instructions in the :ref:`tutorials_transpiler` example. + Executing circuits using the Qibolab backend results to automatic application of the transpilation and compilation pipelines (:ref:`main_doc_compiler`) which convert the circuit to a pulse sequence that is executed by the given platform. + It is possible to modify these pipelines following the instructions in the :ref:`tutorials_compiler` example. QASM Execution -------------- diff --git a/doc/source/tutorials/compiler.rst b/doc/source/tutorials/compiler.rst new file mode 100644 index 000000000..4151831a6 --- /dev/null +++ b/doc/source/tutorials/compiler.rst @@ -0,0 +1,132 @@ +.. _tutorials_compiler: + +How to modify the default circuit transpilation. +================================================ + +A Qibolab platform can execute pulse sequences. +As shown in :ref:`tutorials_circuits`, Qibo circuits can be executed by invoking the :class:`qibolab.backends.QibolabBackend`, which is the object integrating Qibolab to Qibo. +When a Qibo circuit is executed, the backend will automatically transpile and compile it to a pulse sequence, which will be sent to the platform for execution. +The default transpiler and compiler outlined in the :ref:`main_doc_compiler` section will be used in this process. +In this tutorial we will demonstrate how the user can modify this process for custom applications. + +The ``transpiler`` and ``compiler`` objects used when executing a circuit are attributes of :class:`qibolab.backends.QibolabBackend`. +Creating an instance of the backend provides access to these objects: + +.. testcode:: python + + from qibolab.backends import QibolabBackend + + backend = QibolabBackend(platform="dummy") + + print(type(backend.transpiler)) + print(type(backend.compiler)) + +.. testoutput:: python + :hide: + + + + +The transpiler is responsible for transforming any circuit to one that respects +the chip connectivity and native gates. The compiler then transforms this circuit +to the equivalent pulse sequence. +The user can modify the default transpilation and compilation process by changing +the ``transpiler`` and ``compiler`` attributes of the ``QibolabBackend``. + +.. testcode:: python + + from qibo import gates + from qibo.models import Circuit + from qibolab.backends import QibolabBackend + + # define circuit + circuit = Circuit(1) + circuit.add(gates.U3(0, 0.1, 0.2, 0.3)) + circuit.add(gates.M(0)) + + backend = QibolabBackend(platform="dummy") + # disable the transpiler + backend.transpiler = None + + # execute circuit + result = backend.execute_circuit(circuit, nshots=1000) + +completely disables the transpilation steps and the circuit is sent directly to the compiler. + +In this example, we executed circuits using the backend ``backend.execute_circuit`` method, +unlike the previous example (:ref:`tutorials_circuits`) where circuits were executed directly using ``circuit(nshots=1000)``. +It is possible to perform transpiler and compiler manipulation in both approaches. +When using ``circuit(nshots=1000)``, Qibo is automatically initializing a ``GlobalBackend()`` singleton that is used to execute the circuit. +Therefore the previous manipulations can be done as follows: + +.. testcode:: python + + import qibo + from qibo import gates + from qibo.models import Circuit + from qibo.backends import GlobalBackend + + # define circuit + circuit = Circuit(1) + circuit.add(gates.U3(0, 0.1, 0.2, 0.3)) + circuit.add(gates.M(0)) + + # set backend to qibolab + qibo.set_backend("qibolab", platform="dummy") + # disable the transpiler + GlobalBackend().transpiler = None + + # execute circuit + result = circuit(nshots=1000) + + +Defining custom compiler rules +============================== + +The compiler can be modified by adding new compilation rules or changing existing ones. +As explained in :ref:`main_doc_compiler` section, a rule is a function that accepts a Qibo gate and a Qibolab platform +and returns the pulse sequence implementing this gate. + +The following example shows how to modify the transpiler and compiler in order to execute a circuit containing a Pauli X gate using a single pi-pulse: + +.. testcode:: python + + from qibo import gates + from qibo.models import Circuit + from qibolab.backends import QibolabBackend + from qibolab.pulses import PulseSequence + + # define the circuit + circuit = Circuit(1) + circuit.add(gates.X(0)) + circuit.add(gates.M(0)) + + + # define a compiler rule that translates X to the pi-pulse + def x_rule(gate, platform): + """X gate applied with a single pi-pulse.""" + qubit = gate.target_qubits[0] + sequence = PulseSequence() + sequence.add(platform.create_RX_pulse(qubit, start=0)) + return sequence, {} + + + # the empty dictionary is needed because the X gate does not require any virtual Z-phases + + backend = QibolabBackend(platform="dummy") + # disable the transpiler + backend.transpiler = None + # register the new X rule in the compiler + backend.compiler[gates.X] = x_rule + + # execute the circuit + result = backend.execute_circuit(circuit, nshots=1000) + +Here we completely disabled the transpiler to avoid transforming the X gate to a different gate and we added a rule that instructs the compiler how to transform the X gate. + +The default set of compiler rules is defined in :py:mod:`qibolab.compilers.default`. + +.. note:: + If the compiler receives a circuit that contains a gate for which it has no rule, an error will be raised. + This means that the native gate set that the transpiler uses, should be compatible with the available compiler rules. + If the transpiler is disabled, a rule should be available for all gates in the original circuit. diff --git a/doc/source/tutorials/index.rst b/doc/source/tutorials/index.rst index c3e11046d..c904d1932 100644 --- a/doc/source/tutorials/index.rst +++ b/doc/source/tutorials/index.rst @@ -12,4 +12,5 @@ In this section we present code examples from basic to advanced features impleme pulses circuits calibration + compiler instrument