\n", "\n", "## Question 2.1\n", "\n", "Make a new function `circuit_optimizer2` that improves on the one above by:\n", " 1. cancelling adjacent pairs of CNOT and Hadamard gates\n", " 2. adding together the phases in adjacent `XPhase` gates (`rx(.)` gates in QASM)\n", " 3. removing X or Z phase gates with a phase of `0`\n", "\n", "Apply your function to a test circuit and check that it preserves the overall unitary using `zx.compare_tensors`.\n", "\n", "Note: By \"adjacent gates\", we mean gates that are next to each other in the `gates` list with the same `target` property (in the case of Hadamard gates) and the same `control` and `target` properties (for CNOT gates) .\n", "\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "## Question 2.2\n", "\n", "Use `zx.generate.CNOT_HAD_PHASE_circuit` (see [Documentation](https://pyzx.readthedocs.io/en/latest/api.html#generating-circuits)) to generate 100 random circuits with 4, 5, and 6 qubits and gate depth 20. Test your `circuit_optimizer2` function is producing the correct output circuit for each using `zx.compare_tensors`.\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we'll adopt an alternative approach, based on doing ZX-calculus simplifications. First we'll implement a simplifier using some of the techniques we learning in part 1." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "## Question 2.3\n", "\n", "Implement a function called `zx_simplify` that performs spider fusion and removes identities as much as possible on a ZX-diagram. Test your simplifier on random circuits using `zx.tensor_compare` as in question 2.2.\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now comes the tricky part! If we start with a circuit, we can call `c.to_graph()` to get a ZX-diagram, and do all sorts of simplifications using the rules of the ZX-calculus. But how do we get a circuit back out?\n", "\n", "In the general case, this is still an open problem! Solving it in special cases has been the subject of two recent papers:\n", " * [Graph-theoretic Simplification of Quantum Circuits with the ZX-calculus](https://arxiv.org/abs/1902.03178)\n", " * [There and back again: A circuit extraction tale](https://arxiv.org/abs/2003.01664)\n", "\n", "In our case, we started with a circuit and only applied spider-fusion and identity-removal laws. This makes circuit extraction relatively simple: we just need to \"unfuse\" some spiders again to get gates back out.\n", "\n", "Written more algorithmically, we can do the following. Start with a graph and an empty circuit `circ`, and pull spiders and edges out of the graph and turn them into gates in `circ`. That is:\n", " 1. If any of outputs of the graph are connected to Hadamard edges, prepend a Hadamard gate to `circ` and change to normal edges.\n", " 2. If any vertices adjacent to an output are Z or X vertices with degree 2, prepend the appropriate kind of phase gate to `circ`, remove the vertex from the graph, and go to step 1. Otherwise continue.\n", " 3. If any pairs of vertices are both adjacent to outputs and are connected by an edge, delete that edge and prepend the appropriate kind of 2-qubit gate to `circ`. For example, if vertex 1 is a Z vertex and vertex 2 is an X vertex, prepend a CNOT gate to `circ`. If we removed an edge, go back to step 2. Otherwise continue.\n", " 4. If we have managed to remove all Z and X nodes in the previous steps, we will be left just with wires. The only thing left to do is insert SWAP gates at the beginning of the circuit to account for any crossing wires in the graph. If we did NOT remove all of the Z or X spiders, the extraction fails.\n", "\n", "PyZX has a function for this called `zx.extract_simple`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "## Question 2.4\n", "\n", "Implement a function called `zx_circuit_optimizer` that first simplifies the ZX-diagram of a circuit using `zx_simplify` then extracts the result. Test your optimizer on random circuits using `zx.compare_tensors` as in question 2.2.\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "## Question 2.5\n", "\n", "Benchmark the performance of `circuit_optimizer2` and `zx_circuit_optimizer`. That is, provide statistics for how well the optimizer performs at (1) reducing the total gate count and (2) reducing the 2-qubit gate count, for random circuits of various sizes.\n", "\n", "There is no \"right or wrong\" answer to this question, but your results should be informative and you should briefly describe your methodology. For useful methods to analyse circuits, you may wish to have a look at the [documentation](https://pyzx.readthedocs.io/en/latest/api.html).\n", "\n", "
Although it is obviously more fun to run things on a real quantum computer, if you can't get it to work, you can use `noisy_simulator` as the backend for this question and the next one. It should have (approximately) the same behaviour as the \"ibmq_athens\" device.