{"cells":[{"cell_type":"markdown","metadata":{},"source":["# Circuit analysis\n","\n","**Download this notebook - {nb-download}`circuit_analysis_example.ipynb`**"]},{"cell_type":"markdown","metadata":{},"source":["This notebook will introduce the basic methods of analysis and visualization of circuits available in `pytket`.
\n","
\n","It makes use of the modules `pytket_qiskit` and `pytket_cirq` for visualization; these need to be installed (with `pip`) in addition to `pytket`.
\n","
\n","We'll start by generating a small circuit to use as an example, and give it a name."]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["from pytket.circuit import Circuit, OpType"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["c = Circuit(4, name=\"example\")\n","c.add_gate(OpType.CU1, 0.5, [0, 1])\n","c.H(0).X(1).Y(2).Z(3)\n","c.X(0).CX(1, 2).Y(1).Z(2).H(3)\n","c.Y(0).Z(1)\n","c.add_gate(OpType.CU1, 0.5, [2, 3])\n","c.H(2).X(3)\n","c.Z(0).H(1).X(2).Y(3).CX(3, 0)"]},{"cell_type":"markdown","metadata":{},"source":["## Basic statistics"]},{"cell_type":"markdown","metadata":{},"source":["From the circuit we can easily read off the number of qubits ..."]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["c.n_qubits"]},{"cell_type":"markdown","metadata":{},"source":["... the name ..."]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["c.name"]},{"cell_type":"markdown","metadata":{},"source":["... the overall depth of the circuit ..."]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["c.depth()"]},{"cell_type":"markdown","metadata":{},"source":["... and the depth by type of gate:"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["from pytket.circuit import OpType"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["c.depth_by_type(OpType.CU1), c.depth_by_type(OpType.H)"]},{"cell_type":"markdown","metadata":{},"source":["This last method counts the number of instances of the specified gate type that cannot be parallelized. Notice that although there are 4 H gates in the circuit, the H-depth is 2 because pairs of them can be parallelized (as will be clear from the visualizations below)."]},{"cell_type":"markdown","metadata":{},"source":["## Visualization"]},{"cell_type":"markdown","metadata":{},"source":["There are several ways to produce useful visualizations of circuits from `pytket`: we can use the methods in the `pytket.circuit.display` class; we can use the built-in `Graph` class to visualize the circuit as a directed acyclic graph (DAG); we can convert the circuit to either Qiskit or Cirq and use the tools provided by those modules; or we can export to Latex."]},{"cell_type":"markdown","metadata":{},"source":["### Via the `render_circuit_jupyter` method"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["from pytket.circuit.display import render_circuit_jupyter"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["render_circuit_jupyter(c)"]},{"cell_type":"markdown","metadata":{},"source":["Notice that although the `render_circuit_jupyter` method is the recommended way to render a circuit as jupyter cell output, one of the other methods should be used when working with scripts or python shells."]},{"cell_type":"markdown","metadata":{},"source":["### Via the `Graph` class"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["from pytket.utils import Graph"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["G = Graph(c)\n","G.get_DAG()"]},{"cell_type":"markdown","metadata":{},"source":["The small numbers (0 and 1) shown at the entry to and exit from the two-qubit gates represent \"port numbers\" on the gates; these allow us to track individual qubits, which may be placed in a different order on entry and exit in order to simplify the layout.
\n","
\n","The `Graph` class also has methods to save this image to a file and to open it in a PDF viewer.
\n","
\n","We can also view the qubit connectivity graph of a circuit:"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["G.get_qubit_graph()"]},{"cell_type":"markdown","metadata":{},"source":["### Via Qiskit"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["from pytket.extensions.qiskit import tk_to_qiskit"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["print(tk_to_qiskit(c))"]},{"cell_type":"markdown","metadata":{},"source":["### Via Cirq"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["from pytket.extensions.cirq import tk_to_cirq"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["print(tk_to_cirq(c))"]},{"cell_type":"markdown","metadata":{},"source":["(Note that Cirq cannot represent all gates diagrammatically.)"]},{"cell_type":"markdown","metadata":{},"source":["### Via Latex"]},{"cell_type":"markdown","metadata":{},"source":["We can create a Latex document containing a diagram of the circuit using the `to_latex_file()` method. This uses the `quantikz` library. The document can be viewed on its own or the Latex can easily be copied and pasted into a larger document."]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["c.to_latex_file(\"c.tex\")"]},{"cell_type":"markdown","metadata":{},"source":["## Commands"]},{"cell_type":"markdown","metadata":{},"source":["We can retrieve a list of operations comprising a circuit, each represented as a `Command` object:"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["cmds = c.get_commands()\n","print(cmds)"]},{"cell_type":"markdown","metadata":{},"source":["Each `Command` is defined by an operation and the qubits it operates on (as well as the classical bits and conditions, if any). For example:"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["cmd0 = cmds[0]\n","op0 = cmd0.op\n","print(op0)\n","qubits0 = cmd0.args\n","print(qubits0)"]},{"cell_type":"markdown","metadata":{},"source":["From the `Op` we can read off the string representation (in normal or Latex form), the parameters and the type:"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["op0.get_name() # normal form"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["op0.get_name(latex=True) # Latex form"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["op0.type, op0.params"]},{"cell_type":"markdown","metadata":{},"source":["Note that some compilation passes introduce implicit wire swaps at the end of the circuit, which are not represented in the command list. (The internal representation of the circuit as a directed acyclic graph reduces explicit permutations of qubits to implicit features of the graph.)"]}],"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.6.4"}},"nbformat":4,"nbformat_minor":2}