-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathuser_guide.rst
153 lines (101 loc) · 6.31 KB
/
user_guide.rst
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
Unitary Compiler Collection User Guide
######################################
The Unitary Compiler Collection (UCC) is a Python library for frontend-agnostic, high performance compilation\* of quantum circuits.
It can be used with multiple quantum computing frameworks, including `Qiskit <https://github.com/Qiskit/qiskit>`_, `Cirq <https://github.com/quantumlib/Cirq>`_, and `PyTKET <https://github.com/CQCL/tket>`_ via OpenQASM2.
Installation
*************
To install ``ucc`` run:
.. code:: bash
git clone https://github.com/unitaryfund/ucc.git
cd ucc
pip install -e . # Editable mode
UCC requires Python version ≥ 3.12.
Basic usage
***********
To use UCC, one must first specify a circuit in a supported format.
For basic usage, the circuit of interest is simply input into the function ``ucc.compile()``.
The output of ``ucc.compile()`` is a transpiled circuit that is logically equivalent to the input circuit but with reduced gate counts (and by default returned in the same format) as the input circuit.
For example, we can define a random circuit in Qiskit and optimize it using the default settings of ``ucc.compile()``, as shown in the following example.
.. code:: python
from qiskit.circuit.random import random_clifford_circuit
import ucc
from benchmarks.scripts.common import count_multi_qubit_gates_qiskit
gates = ["cx", "cz", "cy", "swap", "x", "y", "z", "s", "sdg", "h"]
num_qubits = 10
raw_circuit = random_clifford_circuit(
num_qubits, gates=gates, num_gates=10 * num_qubits * num_qubits
)
compiled_circuit = ucc.compile(raw_circuit)
print(f"Number of multi-qubit gates in original circuit: {count_multi_qubit_gates_qiskit(raw_circuit)}")
print(f"Number of multi-qubit gates in compiled circuit: {count_multi_qubit_gates_qiskit(compiled_circuit)}")
Key modules
***********
UCC includes the following modules:
- ``quantum_translator`` for translating one circuit representation into another, e.g. Qiskit into Cirq
- ``transpilers`` containing the UCC default transpiler pass sequence and execution flow. UCC default passes, i.e. passes included in ``UCC_Default1`` are:
- ``BasisTranslator``
- ``Optimize1qGatesDecomposition``
- ``CommutativeCancellation``
- ``Collect2qBlocks``
- ``ConsolidateBlocks``
- ``UnitarySynthesis``
- ``Optimize1qGatesDecomposition``
- ``CollectCliffords``
- ``HighLevelSynthesis`` (greedy Clifford synthesis)
- ``transpiler_passes`` consisting of submodules, each designed to perform a different optimization or analysis pass on the circuit.
These include the passes listed in ``UCC_Default1``, along with others for specialized use.
The full list of transpiler passes available in UCC can be found in the :doc:`api`.
Customization
*************
UCC offers different levels of customization, from settings accepted by the "default" pass ``UCCDefault1`` to the ability to add custom transpiler passes.
Transpilation settings
======================
UCC settings can be adjusted using the keyword arguments of the ``ucc.compile()`` function, as shown.
.. code:: python
ucc.compile(
circuit,
return_format="original",
target_device=None,
)
- ``return_format`` is the format in which the input circuit will be returned, e.g. "TKET" or "OpenQASM2". Check ``ucc.supported_circuit_formats()`` for supported circuit formats. Default is the format of input circuit.
- ``target_device`` can be specified as a Qiskit backend or coupling map, or a list of connections between qubits. If None, all-to-all connectivity is assumed. If a Qiskit backend or coupling map is specified, only the coupling list extracted from the backend is used.
Writing a custom pass
=====================
UCC reuses part of the Qiskit transpiler framework for creation of custom transpiler passes, specifically the ``TransformationPass`` type of pass and the ``PassManager`` object for running custom passes and sequences of passes.
In the following example, we demonstrate how to create a custom pass, where the Directed Acycylic Graph (DAG) representation of the circuit is the object manipulated by the pass.
.. code:: python
from qiskit.transpiler.basepasses import TransformationPass
from qiskit.dagcircuit import DAGCircuit
class MyCustomPass(TransformationPass):
def __init__(self):
super().__init__()
def run(self, dag: DAGCircuit) -> DAGCircuit:
# Your code here
return dag
Applying a non-default pass in the transpilation sequence
=========================================================
UCC's built-in pass manager ``UCCDefault1().pass_manager`` can be used to apply a non-default or a custom pass in the sequence of transpilation passes.
In the following example we show how to add passes for merging single qubit rotations interrupted by a commuting 2 qubit gate.
.. code:: python
from qiskit.circuit.equivalence_library import SessionEquivalenceLibrary as sel
from qiskit.transpiler.passes import Optimize1qGatesSimpleCommutation
from ucc import UCCDefault1
from ucc.transpiler_passes import BasisTranslator
single_q_basis = ['rz', 'rx', 'ry', 'h']
target_basis = single_q_basis.append('cx')
ucc_compiler = UCCDefault1()
ucc_compiler.pass_manager.append(Optimize1qGatesSimpleCommutation(basis=single_q_basis))
ucc_compiler.pass_manager.append(BasisTranslator(sel, target_basis=target_basis))
custom_compiled_circuit = ucc_compiler.run(circuit_to_compile)
Alternatively, we can add a custom pass in the sequence, as shown in the following example.
.. code:: python
from ucc import UCCDefault1
ucc_compiler = UCCDefault1()
ucc_compiler.pass_manager.append(MyCustomPass())
custom_compiled_circuit = ucc_compiler.run(circuit_to_compile)
A note on terminology
*********************
.. important::
There is some disagreement in the quantum computing community on the proper usage of the terms "transpilation" and "compilation."
For instance, Qiskit refers to optimization of the Directed Acyclic Graph (DAG) of a circuit as "transpilation," whereas in qBraid, the 1:1 translation of one circuit representation into another without optimization (e.g. a Cirq circuit to a Qiskit circuit; OpenQASM 2 into PyTKET) is called "transpilation."
In addition, Cirq uses the term "transformer" and PyTKET uses :code:`CompilationUnit` to refer to what Qiskit calls a transpiler pass.