from itertools import product
from typing import List, Union
import numpy as np
from quara.objects.composite_system import CompositeSystem
from quara.objects.matrix_basis import (
SparseMatrixBasis,
calc_hermitian_matrix_expansion_coefficient_hermitian_basis,
)
from quara.objects.povm import Povm
from quara.objects.state_typical import (
generate_state_density_mat_from_name,
generate_state_pure_state_vector_from_name,
)
from quara.utils.matrix_util import calc_mat_from_vector_adjoint
[docs]def get_povm_object_names() -> List[str]:
"""Return the list of valid povm-related object names.
Returns
-------
List[str]
the list of valid povm-related object names.
"""
names = ["pure_state_vectors", "matrices", "vectors", "povm"]
return names
[docs]def get_povm_names() -> List[str]:
"""Return the list of valid povm names.
Returns
-------
List[str]
the list of valid povm names.
"""
names = []
names += get_povm_names_1qubit()
names += get_povm_names_2qubit()
names += get_povm_names_3qubit()
names += get_povm_names_1qutrit()
names += get_povm_names_2qutrit()
return names
[docs]def get_povm_names_1qubit() -> List[str]:
"""Return the list of valid povm names on 1-qubit system.
Returns
-------
List[str]
the list of valid povm names on 1-qubit system.
"""
names = ["x", "y", "z"]
return names
def _get_povm_names_2qubit_typical() -> List[str]:
return ["bell"]
[docs]def get_povm_names_2qubit() -> List[str]:
"""Return the list of valid povm names on 2-qubit system.
Returns
-------
List[str]
the list of valid povm names on 2-qubit system.
"""
names = _get_povm_names_2qubit_typical()
names_1qubit = get_povm_names_1qubit()
names += ["_".join(t) for t in product(names_1qubit, repeat=2)]
return names
[docs]def get_povm_names_3qubit() -> List[str]:
"""Return the list of valid povm names on 3-qubit system.
Returns
-------
List[str]
the list of valid povm names on 3-qubit system.
"""
names_1qubit = get_povm_names_1qubit()
names = ["_".join(t) for t in product(names_1qubit, repeat=3)]
return names
[docs]def get_povm_names_1qutrit() -> List[str]:
"""Return the list of valid povm names on 1-qutrit system.
Returns
-------
List[str]
the list of valid povm names on 1-qutrit system.
"""
names = ["01x3", "01y3", "z3", "z2", "02x3", "02y3", "12x3", "12y3"]
return names
[docs]def get_povm_names_2qutrit() -> List[str]:
"""Return the list of valid povm names on 2-qutrit system.
Returns
-------
List[str]
the list of valid povm names on 2-qutrit system.
"""
names_1qutrit = get_povm_names_1qutrit()
names = ["_".join(t) for t in product(names_1qutrit, repeat=2)]
return names
[docs]def get_povm_names_rank1() -> List[str]:
"""Return the list of valid povm names of rank 1.
Returns
-------
List[str]
the list of valid povm names of rank 1.
"""
names = [
"x",
"y",
"z",
"bell",
"z3",
"01x3",
"01y3",
"02x3",
"02y3",
"12x3",
"12y3",
]
return names
[docs]def get_povm_names_not_rank1() -> List[str]:
"""Return the list of valid povm names of not rank 1.
Returns
-------
List[str]
the list of valid povm names of not rank 1.
"""
names = ["z2"]
return names
[docs]def generate_povm_object_from_povm_name_object_name(
povm_name: str,
object_name: str,
c_sys: CompositeSystem = None,
basis: SparseMatrixBasis = None,
is_physicality_required: bool = True,
) -> Union[List[np.ndarray], Povm]:
"""Return a povm-related object.
Parameters
----------
povm_name : str
Valid gate_name. It is given by :func:`~quara.objects.povm_typical.get_povm_names()`
object_name : str
Valid object_name. It is given by :func:`~quara.objects.povm_typical.get_povm_object_names`
c_sys : CompositeSystem, optional
To be given for object_name = 'povm', by default None.
basis : MatrixBasis, optional
To be given for object_name = 'vectors', by default None.
is_physicality_required: bool = True
whether the generated object is physicality required, by default True
Returns
-------
Union[List[np.ndarray], Povm]
.. line-block::
List[np.ndarray]
pure state vectors related elements of POVM for object_name = 'pure_state_vectors'
Complex vectors
list of elements of POVM(matrices) for object_name = 'matrices'
Complex matrices
vectors on Hermitian basis for object_name = 'vectors'
Real vectors
Povm
Povm class for object_name = 'povm'
Raises
------
ValueError
[description]
"""
if object_name == "pure_state_vectors":
obj = generate_povm_pure_state_vectors_from_name(povm_name)
elif object_name == "matrices":
obj = generate_povm_matrices_from_name(povm_name)
elif object_name == "vectors":
obj = generate_povm_vectors_from_name(povm_name, basis)
elif object_name == "povm":
obj = generate_povm_from_name(povm_name, c_sys, is_physicality_required)
else:
raise ValueError(f"object_name is out of range. object_name={object_name}")
return obj
def _generate_povm_pure_state_vectors_from_single_name(
povm_name: str,
) -> List[np.ndarray]:
if povm_name not in get_povm_names_rank1():
raise ValueError(f"povm_name is not rank 1. povm_name={povm_name}")
if povm_name == "x":
pure_state_vector_names = ["x0", "x1"]
elif povm_name == "y":
pure_state_vector_names = ["y0", "y1"]
elif povm_name == "z":
pure_state_vector_names = ["z0", "z1"]
elif povm_name == "bell":
pure_state_vector_names = [
"bell_phi_plus",
"bell_phi_minus",
"bell_psi_plus",
"bell_psi_minus",
]
elif povm_name == "z3":
pure_state_vector_names = ["01z0", "01z1", "02z1"]
elif povm_name == "01x3":
pure_state_vector_names = ["01x0", "01x1", "02z1"]
elif povm_name == "01y3":
pure_state_vector_names = ["01y0", "01y1", "02z1"]
elif povm_name == "02x3":
pure_state_vector_names = ["02x0", "02x1", "01z1"]
elif povm_name == "02y3":
pure_state_vector_names = ["02y0", "02y1", "01z1"]
elif povm_name == "01z3":
pure_state_vector_names = ["01z0", "01z1", "02z1"]
elif povm_name == "12x3":
pure_state_vector_names = ["12x0", "12x1", "01z0"]
elif povm_name == "12y3":
pure_state_vector_names = ["12y0", "12y1", "01z0"]
vectors = [
generate_state_pure_state_vector_from_name(pure_state_vector_name)
for pure_state_vector_name in pure_state_vector_names
]
return vectors
[docs]def generate_povm_pure_state_vectors_from_name(povm_name: str) -> List[np.ndarray]:
"""returns pure state vectors.
Parameters
----------
povm_name : str
name of povm.
Returns
-------
List[np.ndarray]
pure state vectors.
Raises
------
ValueError
povm_name is invalid.
"""
# split and get each pure state vectors
single_povm_names = povm_name.split("_")
pure_state_vectors_list = [
_generate_povm_pure_state_vectors_from_single_name(single_povm_name)
for single_povm_name in single_povm_names
]
# tensor product
temp = pure_state_vectors_list[0]
for pure_state_vectors in pure_state_vectors_list[1:]:
temp = [np.kron(vec1, vec2) for vec1, vec2 in product(temp, pure_state_vectors)]
return temp
def _generate_povm_matrices_from_single_name(povm_name: str) -> List[np.ndarray]:
if povm_name in get_povm_names_rank1():
pure_state_vectors = generate_povm_pure_state_vectors_from_name(povm_name)
matrices = [
calc_mat_from_vector_adjoint(pure_state_vector)
for pure_state_vector in pure_state_vectors
]
else:
if povm_name == "z2":
matrices = [
generate_state_density_mat_from_name("01z0"),
generate_state_density_mat_from_name("01z1")
+ generate_state_density_mat_from_name("02z1"),
]
else:
method_name = "get_povm_" + povm_name.replace("-", "") + "_povm_matrices"
method = eval(method_name)
matrices = method()
return matrices
[docs]def generate_povm_matrices_from_name(povm_name: str) -> List[np.ndarray]:
"""returns list of elements of POVM(matrices).
Parameters
----------
povm_name : str
name of povm.
Returns
-------
List[np.ndarray]
list of elements of POVM(matrices).
Raises
------
ValueError
povm_name is invalid.
"""
# split and get each pure state vectors
single_povm_names = povm_name.split("_")
matrices_list = [
_generate_povm_matrices_from_single_name(single_povm_name)
for single_povm_name in single_povm_names
]
# tensor product
temp = matrices_list[0]
for matrices in matrices_list[1:]:
temp = [np.kron(vec1, vec2) for vec1, vec2 in product(temp, matrices)]
return temp
[docs]def generate_povm_vectors_from_name(
povm_name: str, basis: SparseMatrixBasis
) -> List[np.ndarray]:
"""returns vectors on Hermitian basis.
Parameters
----------
povm_name : str
name of povm.
basis : MatrixBasis
Hermitian basis of povm.
Returns
-------
List[np.ndarray]
vectors on Hermitian basis.
Raises
------
ValueError
povm_name is invalid.
ValueError
basis is not Hermitian.
"""
matrices = generate_povm_matrices_from_name(povm_name)
vecs = [
calc_hermitian_matrix_expansion_coefficient_hermitian_basis(matrix, basis)
for matrix in matrices
]
return vecs
[docs]def generate_povm_from_name(
povm_name: str, c_sys: CompositeSystem, is_physicality_required: bool = True
) -> Povm:
"""returns Povm class.
Parameters
----------
povm_name : str
name of povm.
c_sys : CompositeSystem
CompositeSystem of povm.
is_physicality_required: bool = True
whether the generated object is physicality required, by default True
Returns
-------
Povm
Povm class.
Raises
------
ValueError
povm_name is invalid.
"""
vecs = generate_povm_vectors_from_name(povm_name, c_sys.basis())
return Povm(c_sys, vecs, is_physicality_required=is_physicality_required)
[docs]def get_povm_xxparity_povm_matrices() -> List[List[np.ndarray]]:
"""return the POVM matrices of POVM for `xx-parity`.
:math:`\\frac{1}{2}\\begin{pmatrix} 1 & 0 & 0 & 1 \\\\ 0 & 1 & 1 & 0 \\\\ 0 & 1 & 1 & 0 \\\\ 1 & 0 & 0 & 1 \\end{pmatrix}`
:math:`\\frac{1}{2}\\begin{pmatrix} 1 & 0 & 0 & -1 \\\\ 0 & 1 & -1 & 0 \\\\ 0 & -1 & 1 & 0 \\\\ -1 & 0 & 0 & 1 \\end{pmatrix}`
Returns
-------
List[List[np.ndarray]]
the POVM matrices of POVM for `xx-parity`.
"""
k0 = 0.5 * np.array(
[[1, 0, 0, 1], [0, 1, 1, 0], [0, 1, 1, 0], [1, 0, 0, 1]], dtype=np.complex128
)
k1 = 0.5 * np.array(
[[1, 0, 0, -1], [0, 1, -1, 0], [0, -1, 1, 0], [-1, 0, 0, 1]],
dtype=np.complex128,
)
return [k0, k1]
[docs]def get_povm_zzparity_povm_matrices() -> List[List[np.ndarray]]:
"""return the POVM matrices of POVM for `zz-parity`.
:math:`\\begin{pmatrix} 1 & 0 & 0 & 0 \\\\ 0 & 0 & 0 & 0 \\\\ 0 & 0 & 0 & 0 \\\\ 0 & 0 & 0 & 1 \\end{pmatrix}`
:math:`\\begin{pmatrix} 0 & 0 & 0 & 0 \\\\ 0 & 1 & 0 & 0 \\\\ 0 & 0 & 1 & 0 \\\\ 0 & 0 & 0 & 0 \\end{pmatrix}`
Returns
-------
List[List[np.ndarray]]
the POVM matrices of POVM for `zz-parity`.
"""
k0 = np.array(
[[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 1]], dtype=np.complex128
)
k1 = np.array(
[[0, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 0]], dtype=np.complex128
)
return [k0, k1]