.. GaterAid documentation master file, created by sphinx-quickstart on Thu Nov 28 19:37:48 2024. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. ********************** GaterAid Documentation ********************** .. epigraph:: *"I fear not the man who has applied two gates to two thousand qubits. The man who has applied two thousand gates to two qubits, I fear."* -- S. Tzu, *Ph.D* The GaterAid package provides a simple and intuitive interface for applying common and customisable two-qubit gates to quantum states. See our :doc:`example tutorial notebook ` for a quickstart (or :download:`download it `). The repository for GaterAid can be found on `GitHub `_ and the package contains the following modules: * :mod:`~gateraid.controlled_gates`: provides a selection of common controlled gates, as well as simple cutomisation for controlled gates. * :mod:`~gateraid.gate_base`: provides the base class for all two-qubit gates. * :mod:`~gateraid.other_gates`: provides a selection of common two-qubit gates, as well as simple customisation for local and general gates. * :mod:`~gateraid.quantum_state`: provides the base class for all two-qubit quantum states. * :mod:`~gateraid.utilities`: provides utility functions for the package. For detailed documentation and examples, navigate the contents below. In particular, find examples of how to use GaterAid detailed in the `Examples` section below, or alternatively download the Jupyter notebook `example.ipynb `_ from the repository. .. Add your content using ``reStructuredText`` syntax. See the .. `reStructuredText `_ .. documentation for details. .. toctree:: :maxdepth: 2 :caption: Contents: source/modules Installation ============ GaterAid is hosted on the PyPi package index. Use pip to install GaterAid: .. code:: bash pip install GaterAid Examples ======== To use GaterAid, import it in your Python code: .. code:: python >>> from gateraid import * >>> import numpy as np Quantum States -------------- GaterAid represents quantum states as numpy arrays in the QuantumState class. For example, the state :math:`q:=\frac{1}{\sqrt{2}}(|00\rangle + |11\rangle)` is represented as: .. code:: python >>> q = QuantumState(np.array([1, 0, 0, 1])/np.sqrt(2)) >>> print(q) .. code:: bash State: 0.7071+0j|00> + 0+0j|01> + 0+0j|10> + 0.7071+0j|11> Common Two-Qubit Gates ---------------------- In the :mod:`~gateraid.other_gates` module, GaterAid provides a selection of common two-qubit gates. For example, we can define the controlled-NOT gate (CNOT 1->2) as follows, .. code:: python >>> CX = make_CX() >>> print(CX) .. code:: bash CX1->2 gate with matrix: [[1+0j 0+0j 0+0j 0+0j] [0+0j 1+0j 0+0j 0+0j] [0+0j 0+0j 0+0j 1+0j] [0+0j 0+0j 1+0j 0+0j]] We can apply this gate on our state :math:`q` as follows, .. code:: python >>> CX(q) >>> print(q) .. code:: bash State: 0.7071+0j|00> + 0+0j|01> + 0+0j|10> + 0.7071+0j|11> giving us the expected outcome: :math:`\frac{1}{\sqrt{2}}(|00\rangle + |11\rangle) \mapsto \frac{1}{\sqrt{2}}(|00\rangle + |10\rangle)`. Similarly we can define the reversed anti-controlled phase gate (anti-CZ 2->1) and the SWAP gate (SWAP). .. code:: python >>> CZ = make_CZ(first_qubit_controlled=False, anti-control=True) >>> SWAP = make_SWAP() Each of these can be applied to our state in succesion: .. code:: python >>> CZ(q) >>> print(q) .. code:: bash State: 0.7071+0j|00> + 0+0j|01> + -0.7071+0j|10> + 0+0j|11> .. code:: python >>> SWAP(q) >>> print(q) .. code:: bash State: 0.7071+0j|00> + -0.7071+0j|01> + 0+0j|10> + 0+0j|11> More common gates can be found in the :mod:`~gateraid.other_gates` module. General and Customisable Two-Qubit Gates -------------------------------------- GaterAid also provides classes for general two-qubit gates and allows simple customisation for controlled gates and local gates. For example, we can define a NOT gate acting on only the first qubit (XI) as follows, .. code:: python >>> X = make_X() >>> XI = LocalUnitary(X, 'X', 0) >>> print(XI) .. code:: bash X_I gate with matrix: [[0+0j 0+0j 1+0j 0+0j] [0+0j 0+0j 0+0j 1+0j] [1+0j 0+0j 0+0j 0+0j] [0+0j 1+0j 0+0j 0+0j]] Then after re-initialising our state, we can apply this gate, .. code:: python >>> q = QuantumState(np.array([1, 1, 0, 0])/np.sqrt(2)) >>> XI(q) >>> print(q) .. code:: bash State: 0+0j|00> + 0+0j|01> + 0.7071+0j|10> + 0.7071+0j|11> Alternatively, we can define a controlled-Hadamard gate, .. code:: python >>> q = QuantumState(np.array([0, 0, 1, 1])/np.sqrt(2)) >>> H = make_H() >>> CH = ControlledUnitary(H, 'H') >>> CH(q) >>> print(q) .. code:: bash State: 0+0j|00> + 0+0j|01> + 1+0j|10> + 0+0j|11> Finally, an arbitrary two-qubit gate can be defined in terms of the two-qubit Pauli operators :math:`P_i` and real coefficients :math:`c_i`, as .. math:: U = \exp(i\sum_i c_i P_i) Then for example, we can generate a random unitary gate as follows, .. code:: python >>> coef = np.random.rand(16) >>> pauli_dict = {'II': coef[0], 'IX': coef[1], 'IY': coef[2], 'IZ': coef[3], 'XI': coef[4], 'XX': coef[5], 'XY': coef[6], 'XZ': coef[7], 'YI': coef[8], 'YX': coef[9], 'YY': coef[10], 'YZ': coef[11], 'ZI': coef[12], 'ZX': coef[13], 'ZY': coef[14], 'ZZ': coef[15]} >>> U = GeneralUnitary(pauli_dict) >>> print(U(q)) .. code:: bash State: -0.4403+0.4553j|00> + 0.0794-0.1427j|01> + 0.5642-0.1816j|10> + 0.03915-0.4683j|11> giving us a random final state. More detail of general and customisable gates can be found in :mod:`~gateraid.other_gates` and :mod:`~gateraid.controlled_gates` modules. Enjoy!