Skip to content

Commit

Permalink
remove functions accepting np array as input
Browse files Browse the repository at this point in the history
  • Loading branch information
purva-thakre committed Jun 14, 2021
1 parent bf4daed commit 6506bf9
Show file tree
Hide file tree
Showing 2 changed files with 0 additions and 200 deletions.
102 changes: 0 additions & 102 deletions src/qutip_qip/decompositions/general_decompositions.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,105 +30,3 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
###############################################################################

import numpy as np

def normalize_matrix(input_array)-> np.array:
""" Checks if the input gate's array is normalized or not. If not, makes
sure the input has been normalized.
This function will also check if the input is a valid array and a valid
quantum gate.
Args:
input_array : Matrix of a gate in Numpy array form.
"""
if not isinstance(input_array, np.ndarray):
raise TypeError("Not a valid input : A Numpy input array must be provided.")


if isinstance(input_array, np.ndarray):
if input_array.size==0:
raise ValueError("An empty array was provided as input.")

if input_array.shape == (1,1):
raise ValueError("Provide a larger array as input.")

input_matrix_rows = input_array.shape[0]
input_matrix_columns = input_array.shape[1]
if input_matrix_rows !=input_matrix_columns:
raise ValueError("Input must be a square matrix to be a valid gate.")

if np.linalg.det(input_array) != 1:
if np.linalg.det(input_array) ==0:
raise ZeroDivisionError("Determinant of matrix =0.")
norm_factor = float(1/np.abs(np.linalg.det(input_array)))**0.5
input_array = np.around(norm_factor*input_array,5)
else:
input_array = input_array

return(input_array)

# Note this function is defined for qobj, re-defined here for a numpy array.
# Accessing individual elements of Qobj array could be problematic.
def check_unitary(input_array)-> bool:
"""Checks if the input matrix is unitary or not.
Args:
input_array : Matrix of a gate in Numpy array form.
"""
try:
input_array = normalize_matrix(input_array)
except ZeroDivisionError:
input_array = input_array
identity_matrix = np.eye(input_array.shape[0])
input_array_dagger = input_array.conj().T
check_unitary_left = np.allclose(identity_matrix, np.dot(input_array_dagger,input_array))
check_unitary_right = np.allclose(identity_matrix, np.dot(input_array,input_array_dagger))
if check_unitary_left != check_unitary_right:
raise ArithmeticError("Unitary product assertions do not match.")
check_unitary = check_unitary_left
return(check_unitary)

def extract_global_phase(input_array):
"""Express input array as a product of some global phase factor and a special
unitary matrix array (returned in the form of a list containing `phasegate`
and some other special unitary array).
Args:
input_array : Matrix of a gate in Numpy array form.
"""
if check_unitary(input_array) is True:
try:
input_array = normalize_matrix(input_array)
except ZeroDivisionError:
input_array = input_array

det = np.linalg.det(input_array)
power_factor_based_on_matrix_shape = 1/input_array.shape[0]


sin_value_from_determinant = -det.imag
cos_value_from_determinant = det.real

if cos_value_from_determinant == 0.0:
if sin_value_from_determinant > 0.0:
phase_factor = np.arctan(np.inf)
elif sin_value_from_determinant < 0.0:
phase_factor = np.arctan(-np.inf)
else:
ratio_sin_cos = sin_value_from_determinant/cos_value_from_determinant
phase_factor = np.arctan(ratio_sin_cos)

phase_factor = power_factor_based_on_matrix_shape*phase_factor
phase_exp_value = np.cos(phase_factor) - 1j*np.sin(phase_factor)

# Makes sure the value at |0><0| is positive (not really needed)
if phase_exp_value > 0 and input_array[0][0] <0:
phase_exp_value = - phase_exp_value

input_to_su_from_phase = np.multiply(input_array,phase_exp_value)
return((phase_exp_value,input_to_su_from_phase))

else:
raise ValueError("Input array is not a unitary matrix.")
98 changes: 0 additions & 98 deletions tests/test_general_decompositions.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,101 +30,3 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
###############################################################################
import numpy as np
import pytest
from qutip_qip.decompositions.general_decompositions import (
normalize_matrix, check_unitary, extract_global_phase)
from qutip import Qobj

def test_normalize_matrix_valid_input_not_unitary():
""" Test output when a valid input is provided which is not a unitary.
"""
normalized_M = normalize_matrix(np.array([[1, 2], [3, 4]]))
calculated_M = np.array([[0.70711, 1.41421],[2.12132, 2.82843]])
assert np.array_equal(calculated_M, normalized_M)
assert check_unitary(calculated_M) == False

@pytest.mark.parametrize("invalid_input", (Qobj([[1],[2],[3],[4],[5]]),(1,2),1.0,10))
@pytest.mark.parametrize("method",[normalize_matrix,extract_global_phase,check_unitary])
def test_method_invalid_input(invalid_input,method):
""" Test error when Qobj array is provided as input.
"""
with pytest.raises(TypeError, match="Not a valid input : A Numpy input array must be provided."):
method(invalid_input)

@pytest.mark.parametrize("method",(normalize_matrix,extract_global_phase,check_unitary))
def test_method_empty_array(method):
"""When an empty array is provided as input."""
with pytest.raises(ValueError, match="An empty array was provided as input."):
method(np.array([]))

@pytest.mark.parametrize("input",[np.array([[1,4,3]]),np.array([[1, 2], [3, 4],[5,6]])])
@pytest.mark.parametrize("method",(normalize_matrix,extract_global_phase,check_unitary))
def test_method_non_square_matrix(input,method):
"""Test error is raised when row number and column number of Matrix
are mismatched."""
with pytest.raises(ValueError, match="Input must be a square matrix to be a valid gate."):
method(input)

@pytest.mark.parametrize("method",(normalize_matrix,extract_global_phase,check_unitary))
def test_method_one_element_array(method):
"""Test proper error is raised when 1x1 matrix is provided as input."""
with pytest.raises(ValueError, match="Provide a larger array as input."):
method(np.array([[1]]))

def test_normalize_matrix_zero_determinant():
"""Check if function tries to divide by 0 norm factor.
"""
with pytest.raises(ZeroDivisionError, match="Determinant of matrix =0."):
normalize_matrix(np.array([[0, 0], [0, 0]]))

def test_normalize_matrix_normalized_array():
"""Check if function tries to divide by 0 norm factor.
"""
pauliz = np.multiply(np.array([[1,0],[0,-1]]),1/np.sqrt(2))
calculated_array = normalize_matrix(pauliz)
assert all([out==inp] for out, inp in zip(calculated_array,pauliz))


def test_check_unitary():
"""Tests if input is correctly idenitified as unitary. """
input_array = np.array([[1+1j,1-1j],[1-1j,1+1j]])
assert check_unitary(input_array) == True

def test_extract_global_phase_non_unitary_input():
"""Tests if a proper error is raised when input to the function is not
a unitary."""
with pytest.raises(ValueError, match = "Input array is not a unitary matrix."):
extract_global_phase(np.array([[1, 2], [3, 4]]))

def test_extract_global_phase_valid_input_phase_comparison():
"""Tests if phase is correctly calculated when input is valid. """

# Determinant has real part only
matrix1 = np.multiply(np.array([[1,1],[1,-1]]),1/np.sqrt(2))
determined_list_of_gates = extract_global_phase(matrix1)
determined_phase_value = determined_list_of_gates[0]
actual_phase_value = 1+0j
assert(determined_phase_value==actual_phase_value)


def test_extract_global_phase_valid_input_output_comparison():
"""Tests if product of outputs is equal to input when input is valid. """

# Determinant has real part only
matrix1 = np.multiply(np.array([[1,1],[1,-1]]),1/np.sqrt(2))
determined_list_of_gates = extract_global_phase(matrix1)
determined_phase_value = determined_list_of_gates[0]
calculated_array = np.multiply(determined_list_of_gates[1],determined_phase_value)
assert all([out==inp] for out, inp in zip(calculated_array,matrix1))


def test_extract_global_phase_valid_input_shape_comparison():
"""Tests if shape of array is unchanged by function. """

# Determinant has real part only
matrix1 = np.multiply(np.array([[1,1],[1,-1]]),1/np.sqrt(2))
determined_list_of_gates = extract_global_phase(matrix1)
determined_array_shape = np.shape(determined_list_of_gates[1])
input_array_shape = np.shape(matrix1)
assert all([out==inp] for out, inp in zip(input_array_shape,determined_array_shape))

0 comments on commit 6506bf9

Please sign in to comment.