Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document all supported gates in the notebook. #191

Merged
merged 4 commits into from
Dec 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
Right now this project is in Beta and does not yet follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
Right now this project is in Beta and does not yet follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
Hence, occasionally changes will be backwards incompatible (although they will all be documented here).

## [0.x.x] - xxxx-xx-xx
Expand All @@ -13,7 +13,8 @@ Hence, occasionally changes will be backwards incompatible (although they will a
- Support for W nodes and Z boxes (courtesy of @RazinShaikh).
- Support for poly phases (courtesy of @RazinShaikh)
- Support for Jupyter notebooks in documentation using nbsphinx (courtesy of @dlyongemallo).
- Support for OpenQASM 3.0; added Jupyter notebook documenting supported qasm gates (courtesy of @dlyongemallo).
- Jupyter notebook documenting all supported gates (courtesy of @dlyongemallo).
- Support for OpenQASM 3.0 (courtesy of @dlyongemallo).
- A function `is_well_formed` to check that a graph is a well-formed ZX-diagram (courtesy of @RazinShaikh).
- A function `is_pauli` to check whether a phase is Pauli (courtesy of @y-richie-y)
- A function `GraphDiff` that calculates what actions are needed to bring one graph to another (used in ZXLive).
Expand Down Expand Up @@ -76,7 +77,7 @@ This release adds several new features: support for evaluating ZX-diagrams as te
There is one small breaking change, which is that `Graph.inputs` and `Graph.outputs` are now methods that return a list, instead of being lists themselves.

### Added
- Added support for evaluating ZX-diagrams as tensor networks in [quimb](https://quimb.readthedocs.io/en/latest/index.html) (courtesy of
- Added support for evaluating ZX-diagrams as tensor networks in [quimb](https://quimb.readthedocs.io/en/latest/index.html) (courtesy of
Paul Tirlisan).
- Added [quizx](https://github.com/Quantomatic/quizx) backend for the `Graph` class.
- `Graph` vertices can now carry a `ground` generator. This makes it possible to represent measurements and classical control in the diagrams. See the accompanying [paper](https://arxiv.org/abs/2109.06071) (courtesy of ABorgna).
Expand Down
2 changes: 1 addition & 1 deletion doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ PyZX
:caption: Notebooks:

notebooks/gettingstarted
notebooks/qasm
notebooks/gates

Indices and tables
==================
Expand Down
128 changes: 86 additions & 42 deletions doc/notebooks/qasm.ipynb → doc/notebooks/gates.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
"id": "2b28a205",
"metadata": {},
"source": [
"# Supported OpenQASM Gates\n",
"# Supported Gates\n",
"\n",
"The pyzx library supports a subset of the OpenQASM format.\n",
"The pyzx library supports a variety of gates, including all the commonly-used gates in the OpenQASM standard library. It also supports a subset of the OpenQASM file format.\n",
"\n",
"Here are some examples illustrating the usage:"
]
Expand All @@ -32,8 +32,14 @@
"outputs": [],
"source": [
"import pyzx as zx\n",
"from pyzx.circuit import Circuit\n",
"from pyzx.circuit import Circuit, CNOT\n",
"\n",
"# Add pyzx gates.\n",
"c = Circuit(2)\n",
"c.add_gate(\"CNOT\", 0, 1)\n",
"c.add_gate(CNOT(1, 0))\n",
"\n",
"# Adding qasm gates.\n",
"s = \"\"\"\n",
"OPENQASM 2.0;\n",
"include \"qelib1.inc\";\n",
Expand All @@ -52,7 +58,7 @@
"id": "4fb99b07",
"metadata": {},
"source": [
"The set of supported OpenQASM gates are listed below for reference, using the following function to draw their graphs. (Set `simplify` to `True` to reduce the graphs, and set `show_matrix` to `True` to output their matrices.)"
"The set of supported gates are listed below for reference, using the following function to draw their graphs. (Set `simplify` to `True` to reduce the graphs, and set `show_matrix` to `True` to output their matrices.)"
]
},
{
Expand All @@ -64,15 +70,30 @@
"source": [
"from pyzx.circuit.qasmparser import QASMParser\n",
"\n",
"def draw_qasm_circuit(num_qubits, qasm, simplify=False, show_matrix=False):\n",
" print(qasm)\n",
" g = QASMParser().parse(f\"qreg q[{num_qubits}];\\n\" + qasm, strict=False).to_graph()\n",
"def _print_gate_name(gate):\n",
" print(gate.name + (\" (adjoint)\" if hasattr(gate, \"adjoint\") and gate.adjoint else \"\"))\n",
"\n",
"def draw_zx_diagram(num_qubits, gate_or_qasm, simplify=False, show_matrix=False):\n",
" if isinstance(gate_or_qasm, str):\n",
" qasm = gate_or_qasm\n",
" c = QASMParser().parse(f\"qreg q[{num_qubits}];\\n\" + qasm, strict=False)\n",
" for gate in c.gates:\n",
" _print_gate_name(gate)\n",
" print(qasm)\n",
" else:\n",
" gate = gate_or_qasm\n",
" c = Circuit(num_qubits)\n",
" c.add_gate(gate)\n",
" _print_gate_name(gate)\n",
" print(\"(no simple qasm command)\")\n",
"\n",
" g = c.to_graph()\n",
" if simplify:\n",
" g.auto_detect_io()\n",
" zx.simplify.full_reduce(g)\n",
" g.auto_detect_io()\n",
" zx.simplify.full_reduce(g)\n",
" zx.draw(g)\n",
" if show_matrix:\n",
" print(g.to_matrix())"
" print(g.to_matrix())"
]
},
{
Expand All @@ -92,10 +113,10 @@
"metadata": {},
"outputs": [],
"source": [
"draw_qasm_circuit(1, 'x q;')\n",
"draw_qasm_circuit(1, 'y q;')\n",
"draw_qasm_circuit(1, 'z q;')\n",
"draw_qasm_circuit(1, 'h q;')"
"draw_zx_diagram(1, 'x q;')\n",
"draw_zx_diagram(1, 'y q;')\n",
"draw_zx_diagram(1, 'z q;')\n",
"draw_zx_diagram(1, 'h q;')"
]
},
{
Expand All @@ -115,12 +136,12 @@
"metadata": {},
"outputs": [],
"source": [
"draw_qasm_circuit(1, 'rx(0.125*pi) q;')\n",
"draw_qasm_circuit(1, 'ry(0.125*pi) q;')\n",
"draw_qasm_circuit(1, 'rz(0.125*pi) q;') # can also use 'p' or 'u1'\n",
"draw_zx_diagram(1, 'rx(0.125*pi) q;')\n",
"draw_zx_diagram(1, 'ry(0.125*pi) q;')\n",
"draw_zx_diagram(1, 'rz(0.125*pi) q;') # can also use 'p' or 'u1'\n",
"\n",
"draw_qasm_circuit(1, 'u2(0.125*pi,0.125*pi) q[0];')\n",
"draw_qasm_circuit(1, 'u3(0.125*pi,0.125*pi,0.125*pi) q[0];')"
"draw_zx_diagram(1, 'u2(0.125*pi,0.125*pi) q[0];')\n",
"draw_zx_diagram(1, 'u3(0.125*pi,0.125*pi,0.125*pi) q[0];')"
]
},
{
Expand All @@ -138,12 +159,12 @@
"metadata": {},
"outputs": [],
"source": [
"draw_qasm_circuit(1, 's q;')\n",
"draw_qasm_circuit(1, 'sdg q;')\n",
"draw_qasm_circuit(1, 't q;')\n",
"draw_qasm_circuit(1, 'tdg q;')\n",
"draw_qasm_circuit(1, 'sx q;')\n",
"draw_qasm_circuit(1, 'sxdg q;')"
"draw_zx_diagram(1, 's q;')\n",
"draw_zx_diagram(1, 'sdg q;')\n",
"draw_zx_diagram(1, 't q;')\n",
"draw_zx_diagram(1, 'tdg q;')\n",
"draw_zx_diagram(1, 'sx q;')\n",
"draw_zx_diagram(1, 'sxdg q;')"
]
},
{
Expand All @@ -169,7 +190,7 @@
"metadata": {},
"outputs": [],
"source": [
"draw_qasm_circuit(2, 'swap q[0], q[1];')"
"draw_zx_diagram(2, 'swap q[0], q[1];')"
]
},
{
Expand All @@ -187,8 +208,8 @@
"metadata": {},
"outputs": [],
"source": [
"draw_qasm_circuit(2, 'rxx(0.125*pi) q[0], q[1];')\n",
"draw_qasm_circuit(2, 'rzz(0.125*pi) q[0], q[1];')"
"draw_zx_diagram(2, 'rxx(0.125*pi) q[0], q[1];')\n",
"draw_zx_diagram(2, 'rzz(0.125*pi) q[0], q[1];')"
]
},
{
Expand All @@ -206,11 +227,13 @@
"metadata": {},
"outputs": [],
"source": [
"draw_qasm_circuit(2, 'cx q[0], q[1];')\n",
"draw_qasm_circuit(2, 'cy q[0], q[1];')\n",
"draw_qasm_circuit(2, 'cz q[0], q[1];')\n",
"draw_qasm_circuit(2, 'ch q[0], q[1];')\n",
"draw_qasm_circuit(2, 'csx q[0], q[1];')"
"from pyzx.circuit import XCX\n",
"draw_zx_diagram(2, 'cx q[0], q[1];')\n",
"draw_zx_diagram(2, 'cy q[0], q[1];')\n",
"draw_zx_diagram(2, 'cz q[0], q[1];')\n",
"draw_zx_diagram(2, 'ch q[0], q[1];')\n",
"draw_zx_diagram(2, 'csx q[0], q[1];')\n",
"draw_zx_diagram(2, XCX(0, 1))"
]
},
{
Expand All @@ -230,15 +253,15 @@
"metadata": {},
"outputs": [],
"source": [
"draw_qasm_circuit(2, 'crx(0.125*pi) q[0], q[1];')\n",
"draw_qasm_circuit(2, 'cry(0.125*pi) q[0], q[1];')\n",
"draw_qasm_circuit(2, 'crz(0.125*pi) q[0], q[1];')\n",
"draw_zx_diagram(2, 'crx(0.125*pi) q[0], q[1];')\n",
"draw_zx_diagram(2, 'cry(0.125*pi) q[0], q[1];')\n",
"draw_zx_diagram(2, 'crz(0.125*pi) q[0], q[1];')\n",
"\n",
"# Note that this differs from 'crz' by a relative phase.\n",
"draw_qasm_circuit(2, 'cp(0.125*pi) q[0], q[1];') # can also use 'cphase' or 'cu1'\n",
"draw_zx_diagram(2, 'cp(0.125*pi) q[0], q[1];') # can also use 'cphase' or 'cu1'\n",
"\n",
"draw_qasm_circuit(2, 'cu3(0.125*pi,0.125*pi,0.125*pi) q[0], q[1];')\n",
"draw_qasm_circuit(2, 'cu(0.125*pi,0.125*pi,0.125*pi,0.125*pi) q[0], q[1];')"
"draw_zx_diagram(2, 'cu3(0.125*pi,0.125*pi,0.125*pi) q[0], q[1];')\n",
"draw_zx_diagram(2, 'cu(0.125*pi,0.125*pi,0.125*pi,0.125*pi) q[0], q[1];')"
]
},
{
Expand All @@ -264,7 +287,7 @@
"metadata": {},
"outputs": [],
"source": [
"draw_qasm_circuit(3, 'cswap q[0], q[1], q[2];') # Fredkin"
"draw_zx_diagram(3, 'cswap q[0], q[1], q[2];') # Fredkin"
]
},
{
Expand All @@ -282,8 +305,29 @@
"metadata": {},
"outputs": [],
"source": [
"draw_qasm_circuit(3, 'ccx q[0], q[1], q[2];') # Toffoli\n",
"draw_qasm_circuit(3, 'ccz q[0], q[1], q[2];')"
"draw_zx_diagram(3, 'ccx q[0], q[1], q[2];') # Toffoli\n",
"draw_zx_diagram(3, 'ccz q[0], q[1], q[2];')"
]
},
{
"cell_type": "markdown",
"id": "a79198ef-d527-4c81-bb9f-d5aa9851c266",
"metadata": {},
"source": [
"## Other gates"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bca3b4c3",
"metadata": {},
"outputs": [],
"source": [
"from pyzx.circuit import ParityPhase, FSim\n",
"\n",
"draw_zx_diagram(4, ParityPhase(0.5, 0, 1, 2, 3))\n",
"draw_zx_diagram(2, FSim(0, 1, 1/2, 1))"
]
}
],
Expand Down
2 changes: 1 addition & 1 deletion doc/representations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ The currently supported formats are

To convert a PyZX circuit to these formats, use :meth:`~pyzx.circuit.Circuit.to_qasm`, :meth:`~pyzx.circuit.Circuit.to_quipper`, :meth:`~pyzx.circuit.Circuit.to_qc`.

PyZX also offers a convenience function to construct a circuit out of a string containing QASM code using either :meth:`~pyzx.circuit.Circuit.from_qasm` or :func:`~pyzx.circuit.qasmparser.qasm`. See the `Supported OpenQASM Gates notebook <notebooks/qasm.ipynb>`_ for more details.
PyZX also offers a convenience function to construct a circuit out of a string containing QASM code using either :meth:`~pyzx.circuit.Circuit.from_qasm` or :func:`~pyzx.circuit.qasmparser.qasm`. See the `Supported Gates notebook <notebooks/gates.ipynb>`_ for more details.

To convert a Circuit into a PyZX Graph (i.e. a ZX-diagram), call the method :meth:`~pyzx.circuit.Circuit.to_graph`.

Expand Down
4 changes: 3 additions & 1 deletion pyzx/circuit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@

import numpy as np

from .gates import Gate, gate_types, ZPhase, XPhase, CZ, XCX, CNOT, HAD, SWAP, CCZ, Tofolli, Measurement
from .gates import (Gate, gate_types, NOT, Y, Z, HAD, XPhase, YPhase, ZPhase, U2, U3, S, T, SX, SWAP, RXX, RZZ, CNOT,
CY, CZ, CHAD, CSX, XCX, CRX, CRY, CRZ, CPhase, CU3, CU, CSWAP, Tofolli, CCZ, ParityPhase, FSim,
Measurement)

from ..graph.base import BaseGraph
from ..utils import EdgeType
Expand Down
2 changes: 2 additions & 0 deletions pyzx/circuit/gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -824,6 +824,8 @@ class FSim(Gate):
qsim_name = 'fs'
print_phase = True
def __init__(self, control:int, target:int, theta:FractionLike, phi:FractionLike):
# TODO: this version assumes theta is always (pi/2)
assert theta == Fraction(1, 2)
self.control = control
self.target = target
self.theta = theta
Expand Down