Skip to content

Commit

Permalink
one public function
Browse files Browse the repository at this point in the history
  • Loading branch information
purva-thakre committed Jul 15, 2021
1 parent b554278 commit 6484be2
Show file tree
Hide file tree
Showing 10 changed files with 141 additions and 202 deletions.
21 changes: 0 additions & 21 deletions doc/source/_apidoc/qutip_qip.decompose.rst

This file was deleted.

9 changes: 8 additions & 1 deletion doc/source/_apidoc/qutip_qip.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ Subpackages

qutip_qip.algorithms
qutip_qip.compiler
qutip_qip.decompose
qutip_qip.device
qutip_qip.operations
qutip_qip.transpiler
Expand All @@ -33,6 +32,14 @@ qutip\_qip.circuit\_latex module
:undoc-members:
:show-inheritance:

qutip\_qip.decompose module
---------------------------

.. automodule:: qutip_qip.decompose
:members:
:undoc-members:
:show-inheritance:

qutip\_qip.gates module
-----------------------

Expand Down
1 change: 1 addition & 0 deletions src/qutip_qip/_decomposition_functions/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from ._single_qubit_gate import *
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
import cmath

from qutip import Qobj
from qutip_qip.decompose._utility import check_gate, MethodError, GateError
from qutip_qip._decomposition_functions._utility import (
check_gate,
MethodError,
GateError,
)

from qutip_qip.circuit import QubitCircuit, Gate

Expand Down Expand Up @@ -136,78 +140,6 @@ def _ZXZ_rotation(input_gate, target, num_qubits=1):
return (Rz_alpha, Rx_theta, Rz_beta, Phase_gate)


_rotation_matrices_dictionary = {
"ZYZ": _ZYZ_rotation,
"ZXZ": _ZXZ_rotation,
} # other combinations to add here


def decompose_to_rotation_matrices(input_gate, method, num_qubits, target=0):
r""" An input 1-qubit gate is expressed as a product of rotation matrices
:math:`\textrm{R}_i` and :math:`\textrm{R}_j`.
Here, :math:`i \neq j` and :math:`i, j \in {x, y, z}`.
Based on Lemma 4.1 of https://arxiv.org/abs/quant-ph/9503016v1
.. math::
U = \begin{bmatrix}
a & b \\
-b^* & a^* \\
\end{bmatrix} = \textrm{R}_i(\alpha) \textrm{R}_j(\theta) \textrm{R}_i(\beta)
Parameters
----------
input_gate : :class:`.Qobj`
The matrix that's supposed to be decomposed should be a Qobj.
num_qubits : int
Number of qubits being acted upon by input gate
target : int
If the circuit contains more than 1 qubits then provide target for
single qubit gate.
method : string
Name of the preferred decomposition method
.. list-table::
:widths: auto
:header-rows: 1
* - Method Key
- Method
* - ZYZ
- :math:`\textrm{R}_z(\alpha) \textrm{R}_y(\theta) \textrm{R}_z(\beta)`
* - ZXZ
- :math:`\textrm{R}_z(\alpha) \textrm{R}_x(\theta) \textrm{R}_z(\beta)`
Returns
-------
tuple
The gates in the decomposition are returned as a tuple of :class:`Gate`
objects. This tuple will contain 4 elements per each :math:`1 \times 1`
qubit gate - :math:`\textrm{R}_i(\alpha)`, :math:`\textrm{R}_j(\theta)`,
:math:`\textrm{R}_i(\beta)`, and some global phase gate.
"""
try:
assert num_qubits == 1
except AssertionError:
if target is None and num_qubits > 1:
raise GateError(
"This method is valid for single qubit gates only. Provide a target qubit for single qubit gate."
)

key = _rotation_matrices_dictionary.keys()
if str(method) in key:
method = _rotation_matrices_dictionary[str(method)]
return method(input_gate, target, 1)

else:
raise MethodError("Invalid method chosen.")


# Functions for ABC_decomposition


Expand Down Expand Up @@ -264,89 +196,3 @@ def _ZYZ_pauli_X(input_gate, target, num_qubits=1):
)

return (Rz_A, Ry_A, Pauli_X, Ry_B, Rz_B, Pauli_X, Rz_C, Phase_gate)


_rotation_pauli_matrices_dictionary = {
"ZYZ_PauliX": _ZYZ_pauli_X,
} # other combinations to add here


def ABC_decomposition(input_gate, method, num_qubits, target=0):
r""" An input 1-qubit gate is expressed as a product of rotation matrices
:math:`\textrm{R}_i` and :math:`\textrm{R}_j` and Pauli :math:`\sigma_k`.
Here, :math:`i \neq j` and :math:`i, j, k \in {x, y, z}`.
Based on Lemma 4.3 of https://arxiv.org/abs/quant-ph/9503016v1
.. math::
U = \begin{bmatrix}
a & b \\
-b^* & a^* \\
\end{bmatrix} = \textrm{A} \sigma_k \textrm{B} \sigma_k \textrm{C}
Here,
.. list-table::
:widths: auto
:header-rows: 1
* - Gate Label
- Gate Composition
* - :math:`\textrm{A}`
- :math:`\textrm{R}_i(\alpha) \textrm{R}_j \left(\frac{\theta}{2} \right)`
* - :math:`\textrm{B}`
- :math:`\textrm{R}_j \left(\frac{-\theta}{2} \right) \textrm{R}_i \left(\frac{- \left(\alpha + \beta \right)}{2} \right)`
* - :math:`\textrm{C}`
- :math:`\textrm{R}_i \left(\frac{\left(-\alpha + \beta \right)}{2} \right)`
Parameters
----------
input_gate : :class:`.Qobj`
The matrix that's supposed to be decomposed should be a Qobj.
num_qubits : int
Number of qubits being acted upon by input gate
target : int
If the circuit contains more than 1 qubits then provide target for
single qubit gate.
method : string
Name of the preferred decomposition method
.. list-table::
:widths: auto
:header-rows: 1
* - Method Key
- Method
- :math:`(i,j,k)`
* - ZYZ_PauliX
- :math:`\textrm{A} \textrm{X} \textrm{B} \textrm{X} \textrm{C}`
- :math:`(z,y,x)`
Returns
-------
tuple
The gates in the decomposition are returned as a tuple of :class:`Gate`
objects. This tuple will contain 6 elements per each :math:`1 \times 1`
qubit gate - 2 gates forming :math:`\textrm{A}`, 2 gates forming :math:`\textrm{B}`,
1 gates forming :math:`\textrm{C}`, and some global phase gate.
"""
try:
assert num_qubits == 1
except AssertionError:
if target is None and num_qubits > 1:
raise GateError(
"This method is valid for single qubit gates only. Provide a target qubit for single qubit gate."
)

key = _rotation_pauli_matrices_dictionary.keys()
if str(method) in key:
method = _rotation_pauli_matrices_dictionary[str(method)]
return method(input_gate, target, 1)

else:
raise MethodError("Invalid method chosen.")
File renamed without changes.
115 changes: 115 additions & 0 deletions src/qutip_qip/decompose.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import numpy as np
import cmath

from qutip import Qobj
from qutip_qip._decomposition_functions._utility import (
check_gate,
MethodError,
GateError,
)

from qutip_qip.circuit import QubitCircuit, Gate

from qutip_qip._decomposition_functions._single_qubit_gate import (
_ZYZ_rotation,
_ZXZ_rotation,
_ZYZ_pauli_X,
)

_single_decompositions_dictionary = {
"ZYZ": _ZYZ_rotation,
"ZXZ": _ZXZ_rotation,
"ZYZ_PauliX": _ZYZ_pauli_X,
} # other combinations to add here


def decompose_one_qubit_gate(input_gate, method, num_qubits, target=0):
r""" An input 1-qubit gate is expressed as a product of rotation matrices
:math:`\textrm{R}_i` and :math:`\textrm{R}_j` or as a product of rotation matrices
:math:`\textrm{R}_i` and :math:`\textrm{R}_j` and a Pauli :math:`\sigma_k`.
Here, :math:`i \neq j` and :math:`i, j, k \in {x, y, z}`.
Based on Lemma 4.1 and Lemma 4.3 of https://arxiv.org/abs/quant-ph/9503016v1 respectively.
.. math::
U = \begin{bmatrix}
a & b \\
-b^* & a^* \\
\end{bmatrix} = \textrm{R}_i(\alpha) \textrm{R}_j(\theta) \textrm{R}_i(\beta) = \textrm{A} \sigma_k \textrm{B} \sigma_k \textrm{C}
Here,
* :math:`\textrm{A} = \textrm{R}_i(\alpha) \textrm{R}_j \left(\frac{\theta}{2} \right)`
* :math:`\textrm{B} = \textrm{R}_j \left(\frac{-\theta}{2} \right) \textrm{R}_i \left(\frac{- \left(\alpha + \beta \right)}{2} \right)`
* :math:`\textrm{C} = \textrm{R}_i \left(\frac{\left(-\alpha + \beta \right)}{2} \right)`
Parameters
----------
input_gate : :class:`qutip.Qobj`
The matrix that's supposed to be decomposed should be a Qobj.
num_qubits : int
Number of qubits being acted upon by input gate
target : int
If the circuit contains more than 1 qubits then provide target for
single qubit gate.
method : string
Name of the preferred decomposition method
.. list-table::
:widths: auto
:header-rows: 1
* - Method Key
- Method
* - ZYZ
- :math:`\textrm{R}_z(\alpha) \textrm{R}_y(\theta) \textrm{R}_z(\beta)`
* - ZXZ
- :math:`\textrm{R}_z(\alpha) \textrm{R}_x(\theta) \textrm{R}_z(\beta)`
* - ZYZ_PauliX
- :math:`\textrm{A} \sigma_k \textrm{B} \sigma_k \textrm{C}` :math:`\forall k =x, i =z, j=y`
.. note::
This function is under construction. As more combinations are
added, above table will be updated with their respective keys.
Returns
-------
tuple
The gates in the decomposition are returned as a tuple of :class:`Gate`
objects.
When the input gate is decomposed to product of rotation matrices - tuple
will contain 4 elements per each :math:`1 \times 1`
qubit gate - :math:`\textrm{R}_i(\alpha)`, :math:`\textrm{R}_j(\theta)`,
:math:`\textrm{R}_i(\beta)`, and some global phase gate.
When the input gate is decomposed to product of rotation matrices and Pauli -
tuple will contain 6 elements per each :math:`1 \times 1`
qubit gate - 2 gates forming :math:`\textrm{A}`, 2 gates forming :math:`\textrm{B}`,
1 gates forming :math:`\textrm{C}`, and some global phase gate.
"""
try:
assert num_qubits == 1
except AssertionError:
if target is None and num_qubits > 1:
raise GateError(
"This method is valid for single qubit gates only. Provide a target qubit for single qubit gate."
)

key = _single_decompositions_dictionary.keys()
if str(method) in key:
method = _single_decompositions_dictionary[str(method)]
return method(input_gate, target, 1)

else:
raise MethodError("Invalid method chosen.")
1 change: 0 additions & 1 deletion src/qutip_qip/decompose/__init__.py

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@

from qutip import Qobj, average_gate_fidelity, rand_unitary, sigmax, sigmay, sigmaz

from qutip_qip.decompose.single_qubit_gate import (
from qutip_qip._decomposition_functions._single_qubit_gate import (
_ZYZ_rotation,
_ZXZ_rotation,
ABC_decomposition,
_ZYZ_pauli_X,
decompose_to_rotation_matrices,
)

from qutip_qip.decompose import decompose_one_qubit_gate
from qutip_qip.circuit import decomposed_gates_to_circuit, compute_unitary
from qutip_qip.operations.gates import snot, sqrtnot

Expand Down Expand Up @@ -45,10 +43,10 @@ def test_single_qubit_to_rotations(gate, method):
@pytest.mark.parametrize(
"gate", [H, sigmax, sigmay, sigmaz, SQRTNOT, S, T, rand_unitary(2)]
)
@pytest.mark.parametrize("method", ["ZXZ", "ZYZ"])
@pytest.mark.parametrize("method", ["ZXZ", "ZYZ", "ZYZ_PauliX"])
def test_check_single_qubit_to_decompose_to_rotations(gate, method):
"""Initial matrix and product of final decompositions are same within some phase."""
gate_list = decompose_to_rotation_matrices(gate, method, target, num_qubits)
gate_list = decompose_one_qubit_gate(gate, method, target, num_qubits)
decomposed_gates_circuit = decomposed_gates_to_circuit(gate_list, num_qubits)
decomposed_gates_final_matrix = compute_unitary(decomposed_gates_circuit)
fidelity_of_input_output = average_gate_fidelity(
Expand All @@ -71,18 +69,8 @@ def test_output_is_tuple(gate, method):
@pytest.mark.parametrize(
"gate", [H, sigmax, sigmay, sigmaz, SQRTNOT, S, T, rand_unitary(2)]
)
@pytest.mark.parametrize("method", ["ZXZ", "ZYZ"])
def test_check_single_qubit_to_decompose_to_rotations(gate, method):
"""Initial matrix and product of final decompositions are same within some phase."""
gate_list = decompose_to_rotation_matrices(gate, method, num_qubits, target)
assert isinstance(gate_list, tuple)


@pytest.mark.parametrize(
"gate", [H, sigmax, sigmay, sigmaz, SQRTNOT, S, T, rand_unitary(2)]
)
@pytest.mark.parametrize("method", ["ZYZ_PauliX"])
@pytest.mark.parametrize("method", ["ZXZ", "ZYZ", "ZYZ_PauliX"])
def test_check_single_qubit_to_decompose_to_rotations(gate, method):
"""Initial matrix and product of final decompositions are same within some phase."""
gate_list = ABC_decomposition(gate, method, num_qubits, target)
gate_list = decompose_one_qubit_gate(gate, method, num_qubits, target)
assert isinstance(gate_list, tuple)
Loading

0 comments on commit 6484be2

Please sign in to comment.