Source code for quara.objects.povm

import copy
import itertools
from typing import List, Tuple, Union

import numpy as np
from numpy.testing._private.utils import measure

import quara.utils.matrix_util as mutil
from quara.objects.composite_system import CompositeSystem
from quara.objects.matrix_basis import (
    MatrixBasis,
    convert_vec,
    get_normalized_pauli_basis,
)
from quara.settings import Settings
from quara.objects.qoperation import QOperation


[docs]class Povm(QOperation): """ Positive Operator-Valued Measure """ def __init__( self, c_sys: CompositeSystem, vecs: List[np.ndarray], is_physicality_required: bool = True, is_estimation_object: bool = True, on_para_eq_constraint: bool = True, on_algo_eq_constraint: bool = True, on_algo_ineq_constraint: bool = True, mode_proj_order: str = "eq_ineq", eps_proj_physical: float = None, ): """Constructor Parameters ---------- c_sys : CompositeSystem CompositeSystem of this povm. vecs : List[np.ndarray] list of vec of povm elements. is_physicality_required : bool, optional checks whether the POVM is physically wrong, by default True. all of the following conditions are ``True``, the POVM is physically correct: - It is a set of Hermitian matrices. - It is a set of positive semidefinite matrices. - The sum the elements of is the identity matrix. If you want to ignore the above requirements and create a POVM object, set ``is_physicality_required`` to ``False``. Raises ------ ValueError entries of all vecs are not real numbers. ValueError If the dim in the ``c_sys`` does not match the dim in the ``vecs`` ValueError ``is_physicality_required`` is ``True`` and the gate is not physically correct. """ super().__init__( c_sys=c_sys, is_physicality_required=is_physicality_required, is_estimation_object=is_estimation_object, on_para_eq_constraint=on_para_eq_constraint, on_algo_eq_constraint=on_algo_eq_constraint, on_algo_ineq_constraint=on_algo_ineq_constraint, mode_proj_order=mode_proj_order, eps_proj_physical=eps_proj_physical, ) # Set self._vecs: Tuple[np.ndarray, ...] = tuple(copy.deepcopy(vecs)) for b in self._vecs: b.setflags(write=False) self._num_outcomes = len(self._vecs) self._nums_local_outcomes = [len(self._vecs)] # Validation size = vecs[0].shape self._dim = int(np.sqrt(size[0])) size = [self._dim, self._dim] # whether entries of vec are real numbers for vec in self._vecs: if vec.dtype != np.float64: raise ValueError( f"entries of all vecs must be real numbers. some dtype of vecs are {vec.dtype}" ) # Whether dim of CompositeSystem equals dim of vec if c_sys.dim != self._dim: raise ValueError( f"dim of CompositeSystem must equal dim of vec. dim of CompositeSystem is {c_sys.dim}. dim of vec is {self._dim}" ) # whether the POVM is physically correct if self.is_physicality_required and not self.is_physical(): raise ValueError("the POVM is not physically correct.") def _info(self): info = {} info["Type"] = self.__class__.__name__ info["Dim"] = self.dim info["Number of outcomes"] = len(self.vecs) info["Vecs"] = np.array(self.vecs) return info @property def vecs(self) -> List[np.ndarray]: # read only """Property to get vecs of povm. Returns ------- List[np.ndarray] vecs of povm. """ return self._vecs @property def dim(self) -> int: """returns dim of Povm. Returns ------- int dim of Povm. """ return self._dim @property def num_outcomes(self) -> int: """Property to get the number of POVM elements. Returns ------- int the number of POVM elements. """ return self._num_outcomes @property def nums_local_outcomes(self) -> List[int]: """Property to get the list of the number of POVM elements. Returns ------- List[int] the list of the number of POVM elements. """ return self._nums_local_outcomes
[docs] def is_eq_constraint_satisfied(self, atol: float = None): return self.is_identity_sum(atol)
[docs] def is_ineq_constraint_satisfied(self, atol: float = None): return self.is_positive_semidefinite(atol)
[docs] def set_zero(self): size = self.dim ** 2 new_vecs = [np.zeros(size, dtype=np.float64) for _ in range(len(self.vecs))] self._vecs = new_vecs self._is_physicality_required = False
def _generate_zero_obj(self): size = self.dim ** 2 new_vecs = [np.zeros(size, dtype=np.float64) for _ in range(len(self.vecs))] return new_vecs def _generate_origin_obj(self): size = self.dim ** 2 def generate_vec() -> np.ndarray: return np.hstack( [ np.array([np.sqrt(self.dim) / len(self.vecs)], dtype=np.float64), np.zeros(size - 1, dtype=np.float64), ] ) new_vecs = [generate_vec() for _ in range(len(self.vecs))] return new_vecs
[docs] def to_var(self) -> np.ndarray: return convert_vecs_to_var( c_sys=self.composite_system, vecs=list(self.vecs), on_para_eq_constraint=self.on_para_eq_constraint, )
[docs] def to_stacked_vector(self) -> np.ndarray: stacked_vec = np.hstack(self.vecs) return stacked_vec
[docs] def calc_gradient(self, var_index: int) -> "Povm": povm = calc_gradient_from_povm( self.composite_system, self.vecs, var_index, is_estimation_object=self.is_estimation_object, on_para_eq_constraint=self.on_para_eq_constraint, on_algo_eq_constraint=self.on_algo_eq_constraint, on_algo_ineq_constraint=self.on_algo_ineq_constraint, mode_proj_order=self.mode_proj_order, eps_proj_physical=self.eps_proj_physical, ) return povm
[docs] def calc_proj_eq_constraint(self): if not self.composite_system.is_basis_hermitian: raise ValueError("basis is not hermitian.") size = self.dim ** 2 m = len(self.vecs) # c = [√d/m, 0, 0, ...] c = np.hstack( [ np.array([np.sqrt(self.dim) / m], dtype=np.float64), np.zeros(size - 1, dtype=np.float64), ] ) a_bar = np.sum(np.array(self.vecs), axis=0) / m new_vecs = [] for vec in self.vecs: new_vec = vec - a_bar + c new_vecs.append(new_vec) new_povm = Povm( c_sys=self.composite_system, vecs=new_vecs, is_physicality_required=self.is_physicality_required, is_estimation_object=self.is_estimation_object, on_para_eq_constraint=self.on_para_eq_constraint, on_algo_eq_constraint=self.on_algo_eq_constraint, on_algo_ineq_constraint=self.on_algo_ineq_constraint, mode_proj_order=self.mode_proj_order, eps_proj_physical=self.eps_proj_physical, ) return new_povm
[docs] @staticmethod def calc_proj_eq_constraint_with_var( c_sys: CompositeSystem, var: np.ndarray, on_para_eq_constraint: bool = True, ) -> np.ndarray: """calculates the projection of povm on equal constraint. Parameters ---------- c_sys : CompositeSystem CompositeSystem of this variables. var : np.ndarray variables. on_para_eq_constraint : bool, optional whether this variables is on parameter equality constraint, by default True. Returns ------- np.ndarray the projection of povm on equal constraint. """ # var to vecs vecs = convert_var_to_vecs(c_sys, var, on_para_eq_constraint) # project size = c_sys.dim ** 2 m = len(vecs) # c = [√d/m, 0, 0, ...] c = np.hstack( [ np.array([np.sqrt(c_sys.dim) / m], dtype=np.float64), np.zeros(size - 1, dtype=np.float64), ] ) a_bar = np.sum(np.array(vecs), axis=0) / m new_vecs = [] for vec in vecs: new_vec = vec - a_bar + c new_vecs.append(new_vec) # vecs to var new_var = convert_vecs_to_var(c_sys, new_vecs, on_para_eq_constraint) return new_var
[docs] def calc_proj_ineq_constraint(self) -> "Povm": new_vecs = [] for matrix in self.matrices_with_sparsity(): # calc engenvalues and engenvectors eigenvals, eigenvec = np.linalg.eigh(matrix) # project # |λ0 | # Λ = | ... | # | λd-1| diag = np.diag(eigenvals) diag[diag < 0] = 0 # calc new vecs new_matrix = eigenvec @ diag @ eigenvec.T.conjugate() new_vec = to_vec_from_matrix_with_sparsity( self.composite_system, new_matrix ) new_vecs.append(new_vec) new_povm = Povm( c_sys=self.composite_system, vecs=new_vecs, is_physicality_required=self.is_physicality_required, is_estimation_object=self.is_estimation_object, on_para_eq_constraint=self.on_para_eq_constraint, on_algo_eq_constraint=self.on_algo_eq_constraint, on_algo_ineq_constraint=self.on_algo_ineq_constraint, mode_proj_order=self.mode_proj_order, eps_proj_physical=self.eps_proj_physical, ) return new_povm
[docs] @staticmethod def calc_proj_ineq_constraint_with_var( c_sys: CompositeSystem, var: np.ndarray, on_para_eq_constraint: bool = True, ) -> np.ndarray: """calculates the projection of State on inequal constraint. Parameters ---------- c_sys : CompositeSystem CompositeSystem of this variables. var : np.ndarray variables. on_para_eq_constraint : bool, optional whether this variables is on parameter equality constraint, by default True. Returns ------- np.ndarray the projection of State on inequal constraint. """ # var to matrices matrices = to_matrices_from_var(c_sys, var, on_para_eq_constraint) new_vecs = [] for matrix in matrices: # calc engenvalues and engenvectors eigenvals, eigenvec = np.linalg.eigh(matrix) # project # |λ0 | # Λ = | ... | # | λd-1| diag = np.diag(eigenvals) diag[diag < 0] = 0 # calc new vecs new_matrix = eigenvec @ diag @ eigenvec.T.conjugate() new_vec = to_vec_from_matrix_with_sparsity(c_sys, new_matrix) new_vecs.append(new_vec) # vecs to var new_var = convert_vecs_to_var(c_sys, new_vecs, on_para_eq_constraint) return new_var
def _generate_from_var_func(self): return convert_var_to_povm def _copy(self): return copy.deepcopy(self.vecs)
[docs] def calc_stopping_criterion_birgin_raydan_vectors(self): raise NotImplementedError()
[docs] def is_satisfied_stopping_criterion_birgin_raydan_vectors(self): raise NotImplementedError()
[docs] def is_satisfied_stopping_criterion_birgin_raydan_qoperations(self): raise NotImplementedError()
[docs] def vec(self, index: Union[int, Tuple]) -> np.ndarray: """returns vec of measurement by index. Parameters ---------- index : Union[int, Tuple] index of vec of measurement. if type is int, then regardes it as the index for CompositeSystem. if type is Tuple, then regardes it as the indices for earch ElementalSystems. Returns ------- np.ndarray vec of measurement by index. Raises ------ ValueError length of tuple does not equal length of the list of measurements. IndexError specified index does not exist in the list of measurements. """ if type(index) == tuple: # whether size of tuple equals length of the list of measurements if len(index) != len(self.nums_local_outcomes): raise ValueError( f"length of tuple must equal length of the list of measurements. length of tuple={len(index)}, length of the list of measurements={len(self.nums_local_outcomes)}" ) # calculate index in _vecs by traversing the tuple from the back. # for example, if length of _measurements is 3 and each numbers are len1, len2, len3, # then index in _basis of tuple(x1, x2, x3) can be calculated the following expression: # x1 * (len2 * len3) + x2 * len3 + x3 temp_grobal_index = 0 temp_len = 1 for position, local_index in enumerate(reversed(index)): temp_grobal_index += local_index * temp_len temp_len = temp_len * (self.nums_local_outcomes[position]) return self._vecs[temp_grobal_index] else: return self._vecs[index]
[docs] def matrices(self) -> List[np.ndarray]: """returns matrices of measurements. Returns ------- List[np.ndarray] matrices of measurements. """ matrix_list = [] size = (self.dim, self.dim) for v in self.vecs: matrix = np.zeros(size, dtype=np.complex128) for coefficient, basis in zip(v, self.composite_system.basis()): matrix += coefficient * basis matrix_list.append(matrix) return matrix_list
[docs] def matrices_with_sparsity(self) -> List[np.ndarray]: """returns matrices of measurements. this function uses the scipy.sparse module. Returns ------- List[np.ndarray] matrices of measurements. """ return to_matrices_from_vecs(self.composite_system, self.vecs)
[docs] def matrix(self, index: Union[int, Tuple]) -> np.ndarray: """returns matrix of measurement. Parameters ---------- index : Union[int, Tuple] index of vec of measurement. if type is int, then regardes it as the index for CompositeSystem. if type is Tuple, then regardes it as the indices for earch ElementalSystems. Returns ------- np.ndarray matrix of measurement. """ vec = self.vec(index) size = (self.dim, self.dim) matrix = np.zeros(size, dtype=np.complex128) for coefficient, basis in zip(vec, self.composite_system.basis()): matrix += coefficient * basis return matrix
[docs] def matrix_with_sparsity(self, index: Union[int, Tuple]) -> np.ndarray: """returns matrix of measurement. this function uses the scipy.sparse module. Parameters ---------- index : Union[int, Tuple] index of vec of measurement. if type is int, then regardes it as the index for CompositeSystem. if type is Tuple, then regardes it as the indices for earch ElementalSystems. Returns ------- np.ndarray matrix of measurement. """ vec = self.vec(index) new_vec = c_sys._basis_T_sparse.dot(self.vec) matrix = new_vec.reshape((self.dim, self.dim)) return matrix
[docs] def is_hermitian(self) -> bool: """Returns whether the povm is a set of Hermit matrices. Returns ------- bool If `True`, the povm is a set of Hermit matrices. """ for m in self.matrices_with_sparsity(): if not mutil.is_hermitian(m): return False return True
[docs] def is_positive_semidefinite(self, atol: float = None) -> bool: """Returns whether each element is positive semidifinite. Returns ------- bool True where each element is positive semidifinite, False otherwise. """ atol = Settings.get_atol() if atol is None else atol for m in self.matrices_with_sparsity(): if not mutil.is_positive_semidefinite(m, atol): return False return True
[docs] def is_identity_sum(self, atol: float = None) -> bool: """Returns whether the sum of the elements ``_vecs`` is an identity matrix. Returns ------- bool If the sum of the elements ``_vecs`` is an identity matrix, otherwise it returns False. """ atol = Settings.get_atol() if atol is None else atol sum_matrix = self._sum_matrix() identity = np.identity(self.dim, dtype=np.complex128) return np.allclose(sum_matrix, identity, atol=atol)
def _sum_matrix(self): size = [self.dim, self.dim] sum_matrix = np.zeros(size, dtype=np.complex128) for m in self.matrices_with_sparsity(): sum_matrix += np.reshape(m, size) return sum_matrix
[docs] def calc_eigenvalues( self, index: int = None ) -> Union[List[np.ndarray], np.ndarray]: """Calculates eigenvalues. Parameters ---------- index : int, optional Index to obtain eigenvalues, by default None Returns ------- Union[List[np.ndarray], np.ndarray] eigenvalues. """ size = [self._dim, self._dim] if index is not None: v = self.matrices_with_sparsity()[index] w = np.linalg.eigvalsh(v) w = sorted(w, reverse=True) return w else: w_list = [] for v in self.matrices_with_sparsity(): w = np.linalg.eigvalsh(v) w = sorted(w, reverse=True) w_list.append(w) return w_list
[docs] def convert_basis(self, other_basis: MatrixBasis) -> List[np.ndarray]: """Calculate vector representation for ``other_basis``. Parameters ---------- other_basis : MatrixBasis basis Returns ------- List[np.ndarray] Vector representation after conversion to ``other_basis`` . """ converted_vecs = [] for vec in self.vecs: converted_vecs.append( convert_vec(vec, self.composite_system.basis(), other_basis) ) return converted_vecs
def __getitem__(self, key) -> np.ndarray: # get vec with a serial number. return self._vecs[key] def _add_vec(self, other): if len(self.vecs) != len(other.vecs): message = ( "POVMs of different lengths of vecs can not be added to each other." ) message = ( message + f" len(self.vecs)={len(self.vecs)}, len(other.vecs)={len(other.vecs)}" ) raise ValueError(message) new_vecs = [s + o for s, o in zip(self, other)] return new_vecs def _sub_vec(self, other): if len(self.vecs) != len(other.vecs): message = ( "POVMs of different lengths of vecs can not be added to each other." ) message = ( message + f" len(self.vecs)={len(self.vecs)}, len(other.vecs)={len(other.vecs)}" ) raise ValueError(message) new_vecs = [s - o for s, o in zip(self, other)] return new_vecs def _mul_vec(self, other): new_vecs = [vec * other for vec in self.vecs] return new_vecs def _truediv_vec(self, other): with np.errstate(divide="ignore"): new_vecs = [vec / other for vec in self.vecs] return new_vecs
[docs] @staticmethod def convert_var_to_stacked_vector( c_sys: CompositeSystem, var: np.ndarray, on_para_eq_constraint: bool = True, ) -> np.ndarray: """converts variables of povm to stacked vector of povm. Parameters ---------- c_sys : CompositeSystem CompositeSystem of this povm. var : np.ndarray variables of povm. on_para_eq_constraint : bool, optional uses equal constraints, by default True. Returns ------- np.ndarray stacked vector of povm. """ if on_para_eq_constraint: vecs = convert_var_to_vecs(c_sys, var, on_para_eq_constraint) stacked_vector = np.hstack(vecs) else: stacked_vector = var return stacked_vector
[docs] @staticmethod def convert_stacked_vector_to_var( c_sys: CompositeSystem, stacked_vector: np.ndarray, on_para_eq_constraint: bool = True, ) -> np.ndarray: """converts stacked vector of povm to variables of povm. Parameters ---------- c_sys : CompositeSystem CompositeSystem of this povm. stacked_vector : np.ndarray stacked vector of povm. on_para_eq_constraint : bool, optional uses equal constraints, by default True. Returns ------- np.ndarray variables of povm. """ if on_para_eq_constraint: vecs = convert_var_to_vecs( c_sys, stacked_vector, on_para_eq_constraint=False ) var = convert_vecs_to_var(c_sys, vecs, on_para_eq_constraint) else: var = stacked_vector return var
[docs]def to_matrices_from_vecs( c_sys: CompositeSystem, vecs: List[np.ndarray] ) -> List[np.ndarray]: """returns matrices of measurements. Parameters ---------- c_sys : CompositeSystem CompositeSystem of this povm. List[np.ndarray] matrices of vec of this povm. Returns ------- List[np.ndarray] matrices of measurements. """ matrices = [] for vec in vecs: new_vec = c_sys._basis_T_sparse.dot(vec) matrix = new_vec.reshape((c_sys.dim, c_sys.dim)) matrices.append(matrix) return matrices
[docs]def to_vec_from_matrix_with_sparsity( c_sys: CompositeSystem, matrix: np.ndarray ) -> np.ndarray: """converts matrix to vec. this function uses the scipy.sparse module. Parameters ---------- c_sys : CompositeSystem CompositeSystem of this povm. matrix : np.ndarray matrix of vec of this povm. Returns ------- np.ndarray vec of variables. """ vec = c_sys._basisconjugate_sparse.dot(matrix.flatten()) return mutil.truncate_hs(vec)
[docs]def to_vecs_from_matrices_with_sparsity( c_sys: CompositeSystem, matrices: List[np.ndarray] ) -> np.ndarray: """converts matrices to vecs. this function uses the scipy.sparse module. Parameters ---------- c_sys : CompositeSystem CompositeSystem of this povm. matrices : List[np.ndarray] matrices of this povm. Returns ------- np.ndarray vecs of variables. """ vecs = [] for matrix in matrices: new_vec = to_vec_from_matrix_with_sparsity(c_sys, matrix) vecs.append(new_vec) return vecs
[docs]def to_matrices_from_var( c_sys: CompositeSystem, var: np.ndarray, on_para_eq_constraint: bool = True, ) -> List[np.ndarray]: """converts var to matrices. Parameters ---------- c_sys : CompositeSystem CompositeSystem of this povm. var : np.ndarray variables of povm elements. on_para_eq_constraint : bool, optional uses equal constraints, by default True. Returns ------- List[np.ndarray] matrices of this povm. """ # var to vecs vecs = convert_var_to_vecs(c_sys, var, on_para_eq_constraint) # vecs to matrices matrices = to_matrices_from_vecs(c_sys, vecs) return matrices
[docs]def to_var_from_matrices( c_sys: CompositeSystem, matrices: List[np.ndarray], on_para_eq_constraint: bool = True, ) -> np.ndarray: """converts matrices to var. Parameters ---------- c_sys : CompositeSystem CompositeSystem of this povm. matrices : List[np.ndarray] matrices of this povm. on_para_eq_constraint : bool, optional uses equal constraints, by default True. Returns ------- np.ndarray variables of povm elements. """ # matrices to vecs vecs = to_vecs_from_matrices_with_sparsity(c_sys, matrices) # vecs to var var = convert_vecs_to_var(c_sys, vecs, on_para_eq_constraint) return var
[docs]def convert_var_index_to_povm_index( c_sys: CompositeSystem, vecs: List[np.ndarray], var_index: int, on_para_eq_constraint: bool = True, ) -> Tuple[int, int]: """converts variable index to povm index. Parameters ---------- c_sys : CompositeSystem CompositeSystem of this gate. vecs : List[np.ndarray] list of vec of povm elements. var_index : int variable index. on_para_eq_constraint : bool, optional uses equal constraints, by default True. Returns ------- Tuple[int, int] povm index. first value of tuple is an index of the number of measurements. second value of tuple is an index in specific measurement. """ size = vecs[0].shape[0] (num_measurement, measurement_index) = divmod(var_index, size) return (num_measurement, measurement_index)
[docs]def convert_povm_index_to_var_index( c_sys: CompositeSystem, vecs: List[np.ndarray], povm_index: Tuple[int, int], on_para_eq_constraint: bool = True, ) -> int: """converts povm index to variable index. Parameters ---------- c_sys : CompositeSystem CompositeSystem of this gate. vecs : List[np.ndarray] list of vec of povm elements. povm_index : Tuple[int, int] povm index. first value of tuple is an index of the number of measurements. second value of tuple is an index in specific measurement. on_para_eq_constraint : bool, optional uses equal constraints, by default True. Returns ------- int variable index. """ size = vecs[0].shape[0] (num_measurement, measurement_index) = povm_index var_index = size * num_measurement + measurement_index return var_index
[docs]def convert_var_to_vecs( c_sys: CompositeSystem, var: np.ndarray, on_para_eq_constraint: bool = True ) -> List[np.ndarray]: """converts variables to vecs. Parameters ---------- c_sys : CompositeSystem CompositeSystem of this gate. var : np.ndarray variables of povm elements. on_para_eq_constraint : bool, optional uses equal constraints, by default True. Returns ------- List[np.ndarray] list of vec of povm elements. """ vecs = copy.copy(var) dim = c_sys.dim if on_para_eq_constraint: measurement_n = var.shape[0] // (dim ** 2) + 1 # [√d, 0, 0...] total_vecs = np.hstack( [ np.array(np.sqrt(dim)), np.zeros( dim ** 2 - 1, ), ] ) pre_vecs = vecs.reshape(measurement_n - 1, dim ** 2) last_vec = total_vecs - pre_vecs.sum(axis=0) vecs = np.append(pre_vecs, last_vec) else: measurement_n = var.shape[0] // (dim ** 2) vec_list = [] reshaped_vecs = vecs.reshape(measurement_n, dim ** 2) # convert np.ndarray to list of np.ndarray for vec in reshaped_vecs: vec_list.append(vec) return vec_list
[docs]def convert_var_to_povm( c_sys: CompositeSystem, var: np.ndarray, is_physicality_required: bool = True, is_estimation_object: bool = True, on_para_eq_constraint: bool = True, on_algo_eq_constraint: bool = True, on_algo_ineq_constraint: bool = True, mode_proj_order: str = "eq_ineq", eps_proj_physical: float = None, ) -> Povm: """converts vec of variables to povm. Parameters ---------- c_sys : CompositeSystem CompositeSystem of this povm. var : List[np.ndarray] list of vec of povm elements. on_para_eq_constraint : bool, optional uses equal constraints, by default True. Returns ------- Povm converted povm. """ vec_list = convert_var_to_vecs(c_sys, var, on_para_eq_constraint) povm = Povm( c_sys, vec_list, is_physicality_required=is_physicality_required, is_estimation_object=is_estimation_object, on_para_eq_constraint=on_para_eq_constraint, on_algo_eq_constraint=on_algo_eq_constraint, on_algo_ineq_constraint=on_algo_ineq_constraint, mode_proj_order=mode_proj_order, eps_proj_physical=eps_proj_physical, ) return povm
[docs]def convert_vecs_to_var( c_sys: CompositeSystem, vecs: List[np.ndarray], on_para_eq_constraint: bool = True ) -> np.ndarray: """converts hs of povm to vec of variables. Parameters ---------- c_sys : CompositeSystem CompositeSystem of this state. vecs : List[np.ndarray] list of vec of povm elements. on_para_eq_constraint : bool, optional uses equal constraints, by default True. Returns ------- np.ndarray list of vec of variables. """ var = copy.copy(vecs) if on_para_eq_constraint: del var[-1] var = np.hstack(var) return var
[docs]def calc_gradient_from_povm( c_sys: CompositeSystem, vecs: List[np.ndarray], var_index: int, is_estimation_object: bool = True, on_para_eq_constraint: bool = True, on_algo_eq_constraint: bool = True, on_algo_ineq_constraint: bool = True, mode_proj_order: str = "eq_ineq", eps_proj_physical: float = None, ) -> Povm: """calculates gradient from gate. Parameters ---------- c_sys : CompositeSystem CompositeSystem of this gate. vecs : List[np.ndarray] list of vec of povm elements. var_index : int variable index. on_para_eq_constraint : bool, optional uses equal constraints, by default True. Returns ------- Povm Povm with gradient as vecs. """ gradient = [] for _ in vecs: gradient.append(np.zeros(c_sys.dim ** 2, dtype=np.float64)) (num_measurement, measurement_index) = convert_var_index_to_povm_index( c_sys, vecs, var_index, on_para_eq_constraint ) gradient[num_measurement][measurement_index] = 1 povm = Povm( c_sys, gradient, is_physicality_required=False, is_estimation_object=is_estimation_object, on_para_eq_constraint=on_para_eq_constraint, on_algo_eq_constraint=on_algo_eq_constraint, on_algo_ineq_constraint=on_algo_ineq_constraint, mode_proj_order=mode_proj_order, eps_proj_physical=eps_proj_physical, ) return povm
def _get_1q_povm_from_vecs_on_pauli_basis( c_sys: CompositeSystem, vecs: np.ndarray ) -> Povm: # whether CompositeSystem is 1 qubit size = len(c_sys._elemental_systems) if size != 1: raise ValueError(f"CompositeSystem must be 1 qubit. it is {size} qubits") # whether dim of CompositeSystem equals 2 if c_sys.dim != 2: raise ValueError( f"dim of CompositeSystem must equals 2. dim of CompositeSystem is {c_sys.dim}" ) # convert "vecs in Pauli basis" to "vecs in basis of CompositeSystem" to_vecs = [ convert_vec(vec, get_normalized_pauli_basis(), c_sys.basis()).real.astype( np.float64 ) for vec in vecs ] povm = Povm(c_sys, to_vecs) return povm def _get_x_povm_vecs() -> List[np.ndarray]: vecs = [ 1 / np.sqrt(2) * np.array([1, 1, 0, 0], dtype=np.float64), 1 / np.sqrt(2) * np.array([1, -1, 0, 0], dtype=np.float64), ] return vecs def _get_y_povm_vecs() -> List[np.ndarray]: vecs = [ 1 / np.sqrt(2) * np.array([1, 0, 1, 0], dtype=np.float64), 1 / np.sqrt(2) * np.array([1, 0, -1, 0], dtype=np.float64), ] return vecs def _get_z_povm_vecs() -> List[np.ndarray]: vecs = [ 1 / np.sqrt(2) * np.array([1, 0, 0, 1], dtype=np.float64), 1 / np.sqrt(2) * np.array([1, 0, 0, -1], dtype=np.float64), ] return vecs
[docs]def get_x_povm(c_sys: CompositeSystem) -> Povm: """returns POVM of X measurement. Parameters ---------- c_sys : CompositeSystem CompositeSystem containing POVM. Returns ------- Povm X measurement. Raises ------ ValueError CompositeSystem is not 1quit. ValueError dim of CompositeSystem does not equal 2 """ povm = _get_1q_povm_from_vecs_on_pauli_basis(c_sys, _get_x_povm_vecs()) return povm
[docs]def get_y_povm(c_sys: CompositeSystem) -> Povm: """returns POVM of Y measurement. Parameters ---------- c_sys : CompositeSystem CompositeSystem containing POVM. Returns ------- Povm Y measurement. Raises ------ ValueError CompositeSystem is not 1quit. ValueError dim of CompositeSystem does not equal 2 """ povm = _get_1q_povm_from_vecs_on_pauli_basis(c_sys, _get_y_povm_vecs()) return povm
[docs]def get_z_povm(c_sys: CompositeSystem) -> Povm: """returns POVM of Z measurement. Parameters ---------- c_sys : CompositeSystem CompositeSystem containing POVM. Returns ------- Povm Z measurement. Raises ------ ValueError CompositeSystem is not 1quit. ValueError dim of CompositeSystem does not equal 2 """ povm = _get_1q_povm_from_vecs_on_pauli_basis(c_sys, _get_z_povm_vecs()) return povm
def _get_2q_povm_from_vecs_on_pauli_basis( c_sys: CompositeSystem, vecs1: np.ndarray, vecs2: np.ndarray ) -> Povm: # whether CompositeSystem is 2 qubit size = len(c_sys._elemental_systems) if size != 2: raise ValueError(f"CompositeSystem must be 2 qubit. it is {size} qubits") # whether dim of CompositeSystem equals 4 if c_sys.dim != 4: raise ValueError( f"dim of CompositeSystem must equals 4. dim of CompositeSystem is {c_sys.dim}" ) # calculate tensor products of vecs vecs = [np.kron(val1, val2) for val1, val2 in itertools.product(vecs1, vecs2)] # convert "vecs in Pauli basis" to "vecs in basis of CompositeSystem" to_vecs = [ convert_vec( vec, get_normalized_pauli_basis(n_qubit=2), c_sys.basis() ).real.astype(np.float64) for vec in vecs ] povm = Povm(c_sys, to_vecs) return povm
[docs]def get_xx_povm(c_sys: CompositeSystem) -> Povm: """returns POVM of XX measurement. Parameters ---------- c_sys : CompositeSystem CompositeSystem containing POVM. Returns ------- Povm XX measurement. Raises ------ ValueError CompositeSystem is not 2quit. ValueError dim of CompositeSystem does not equal 4 """ povm = _get_2q_povm_from_vecs_on_pauli_basis( c_sys, _get_x_povm_vecs(), _get_x_povm_vecs() ) return povm
[docs]def get_xy_povm(c_sys: CompositeSystem) -> Povm: """returns POVM of XY measurement. Parameters ---------- c_sys : CompositeSystem CompositeSystem containing POVM. Returns ------- Povm XY measurement. Raises ------ ValueError CompositeSystem is not 2quit. ValueError dim of CompositeSystem does not equal 4 """ povm = _get_2q_povm_from_vecs_on_pauli_basis( c_sys, _get_x_povm_vecs(), _get_y_povm_vecs() ) return povm
[docs]def get_xz_povm(c_sys: CompositeSystem) -> Povm: """returns POVM of XZ measurement. Parameters ---------- c_sys : CompositeSystem CompositeSystem containing POVM. Returns ------- Povm XZ measurement. Raises ------ ValueError CompositeSystem is not 2quit. ValueError dim of CompositeSystem does not equal 4 """ povm = _get_2q_povm_from_vecs_on_pauli_basis( c_sys, _get_x_povm_vecs(), _get_z_povm_vecs() ) return povm
[docs]def get_yx_povm(c_sys: CompositeSystem) -> Povm: """returns POVM of YX measurement. Parameters ---------- c_sys : CompositeSystem CompositeSystem containing POVM. Returns ------- Povm YX measurement. Raises ------ ValueError CompositeSystem is not 2quit. ValueError dim of CompositeSystem does not equal 4 """ povm = _get_2q_povm_from_vecs_on_pauli_basis( c_sys, _get_y_povm_vecs(), _get_x_povm_vecs() ) return povm
[docs]def get_yy_povm(c_sys: CompositeSystem) -> Povm: """returns POVM of YY measurement. Parameters ---------- c_sys : CompositeSystem CompositeSystem containing POVM. Returns ------- Povm YY measurement. Raises ------ ValueError CompositeSystem is not 2quit. ValueError dim of CompositeSystem does not equal 4 """ povm = _get_2q_povm_from_vecs_on_pauli_basis( c_sys, _get_y_povm_vecs(), _get_y_povm_vecs() ) return povm
[docs]def get_yz_povm(c_sys: CompositeSystem) -> Povm: """returns POVM of YZ measurement. Parameters ---------- c_sys : CompositeSystem CompositeSystem containing POVM. Returns ------- Povm YZ measurement. Raises ------ ValueError CompositeSystem is not 2quit. ValueError dim of CompositeSystem does not equal 4 """ povm = _get_2q_povm_from_vecs_on_pauli_basis( c_sys, _get_y_povm_vecs(), _get_z_povm_vecs() ) return povm
[docs]def get_zx_povm(c_sys: CompositeSystem) -> Povm: """returns POVM of ZX measurement. Parameters ---------- c_sys : CompositeSystem CompositeSystem containing POVM. Returns ------- Povm ZX measurement. Raises ------ ValueError CompositeSystem is not 2quit. ValueError dim of CompositeSystem does not equal 4 """ povm = _get_2q_povm_from_vecs_on_pauli_basis( c_sys, _get_z_povm_vecs(), _get_x_povm_vecs() ) return povm
[docs]def get_zy_povm(c_sys: CompositeSystem) -> Povm: """returns POVM of ZY measurement. Parameters ---------- c_sys : CompositeSystem CompositeSystem containing POVM. Returns ------- Povm ZY measurement. Raises ------ ValueError CompositeSystem is not 2quit. ValueError dim of CompositeSystem does not equal 4 """ povm = _get_2q_povm_from_vecs_on_pauli_basis( c_sys, _get_z_povm_vecs(), _get_y_povm_vecs() ) return povm
[docs]def get_zz_povm(c_sys: CompositeSystem) -> Povm: """returns POVM of ZZ measurement. Parameters ---------- c_sys : CompositeSystem CompositeSystem containing POVM. Returns ------- Povm ZZ measurement. Raises ------ ValueError CompositeSystem is not 2quit. ValueError dim of CompositeSystem does not equal 4 """ povm = _get_2q_povm_from_vecs_on_pauli_basis( c_sys, _get_z_povm_vecs(), _get_z_povm_vecs() ) return povm