Povm and povm_typical
[1]:
import numpy as np
np.set_printoptions(linewidth=200)
Povm
Quantum measurement has two mathematical treatments. One is positive operator-valued measure (POVM), which can describe the effect of quantum measurement on the probability distribution of its measurement outcome only. The other is measurement apparatus, which can describe both of the effect on the probability distribution and states after the measurement. Current version of quara prepare a class for POVM only. A class for measurement apparatus will be added in the near future.
vecs.vecs of \(\Pi\) is a list of \([ 1/\sqrt{2}, 0, 0, 1/\sqrt{2} ]\) and \([ 1/\sqrt{2}, 0, 0, -1/\sqrt{2} ]\).The methods for generating a State includes the following:
Generate from
povm_typicalmoduleGenerate Povm object directly
Generate from povm_typical module by specifying CompositeSystem and povm name (ex. “z”).
[2]:
from quara.objects.composite_system_typical import generate_composite_system
from quara.objects.povm_typical import generate_povm_from_name
c_sys = generate_composite_system("qubit", 1)
povm = generate_povm_from_name("z", c_sys)
print(povm)
Type:
Povm
Dim:
2
Number of outcomes:
2
Vecs:
[[ 0.70710678 0. 0. 0.70710678]
[ 0.70710678 0. 0. -0.70710678]]
Generate Povm object directly using CompositeSystem and a list of numpy array.
[3]:
from quara.objects.composite_system import CompositeSystem
from quara.objects.elemental_system import ElementalSystem
from quara.objects.matrix_basis import get_normalized_pauli_basis
from quara.objects.povm import Povm
basis = get_normalized_pauli_basis(1)
e_sys = ElementalSystem(0, basis)
c_sys = CompositeSystem([e_sys])
vec1 = np.array([1, 0, 0, 1]) / np.sqrt(2)
vec2 = np.array([1, 0, 0, -1]) / np.sqrt(2)
vecs = [vec1, vec2]
povm = Povm(c_sys, vecs)
print(povm)
Type:
Povm
Dim:
2
Number of outcomes:
2
Vecs:
[[ 0.70710678 0. 0. 0.70710678]
[ 0.70710678 0. 0. -0.70710678]]
specific properties
The property vecs of Povm is a list of a numpy array specified by the constructor argument vecs.
[4]:
povm = Povm(c_sys, vecs)
print(f"vecs: \n{povm.vecs}")
vecs:
(array([0.70710678, 0. , 0. , 0.70710678]), array([ 0.70710678, 0. , 0. , -0.70710678]))
The property dim of Povm is a square root of the size of element of vecs.
[5]:
print(f"dim: {povm.dim}")
print(f"square root of the size of element of vecs: {int(np.sqrt(len(vecs[0])))}")
dim: 2
square root of the size of element of vecs: 2
The property num_outcomes of Povm is the number of POVM elements.
[6]:
print(f"num_outcomes: {povm.num_outcomes}")
print(f"number of POVM elements: {len(vecs)}")
num_outcomes: 2
number of POVM elements: 2
functions to check constraints
The is_eq_constraint_satisfied() function returns True, if and only if \(\sum_x \Pi_x = I\), where \(\Pi_x\) are Povm elements.
[7]:
from operator import add
from functools import reduce
print(f"is_eq_constraint_satisfied(): {povm.is_eq_constraint_satisfied()}")
print(f"sum of matrices: \n{reduce(add, povm.matrices())}")
is_eq_constraint_satisfied(): True
sum of matrices:
[[1.+0.j 0.+0.j]
[0.+0.j 1.+0.j]]
The is_ineq_constraint_satisfied() function returns True, if and only if all \(\Pi_x\) are positive semidifinite matrices.
[8]:
print(f"is_eq_constraint_satisfied(): {povm.is_eq_constraint_satisfied()}")
print(f"matrix(0): \n{povm.matrix(0)}")
print(f"matrix(1): \n{povm.matrix(1)}")
is_eq_constraint_satisfied(): True
matrix(0):
[[1.+0.j 0.+0.j]
[0.+0.j 0.+0.j]]
matrix(1):
[[0.+0.j 0.+0.j]
[0.+0.j 1.+0.j]]
projection functions
calc_proj_eq_constraint() function calculates the projection of Povm on equal constraint.num_outcomes = \(m\), dim = \(d\), and \(\tilde{I} = I/\sqrt{d}\). Then \(\sum_{x=0}^{m-1} \Pi_x = I = \sqrt{d} \cdot \tilde{I}\).\(|\Pi_x\rangle\rangle = [a_{x,0}, \dots, a_{x,d^2-1}]^T\)
\(\bar{a_\alpha} := \frac{1}{m} \sum_{x=0}^{m-1} (|\Pi_x\rangle\rangle)_\alpha\), where \(\alpha = 0, \dots, d^2-1\).
\(c_\alpha := \begin{cases} \sqrt{d}/m & (\alpha = 0) \\ 0 & (\alpha = 1, \dots, d^2-1) \end{cases}\)
\(a_{x,\alpha}^\prime := a_{x,\alpha} - \bar{a_\alpha} + c_\alpha\)
The projection of Povm \(|\tilde{\Pi}_x\rangle\rangle\) is \([ a_{x,0}^\prime, \dots, a_{x,d^2-1}^\prime ]^T\).
This function replaces the last element of vecs with \(1/\sqrt{d}\), where \(d\) is dim.
[9]:
vec1 = np.array([1.0, 2.0, 3.0, 4.0])
vec2 = np.array([5.0, 6.0, 7.0, 8.0])
vecs = [vec1, vec2]
[10]:
povm = Povm(c_sys, vecs, is_physicality_required=False)
proj_povm = povm.calc_proj_eq_constraint()
print(f"vecs: \n{proj_povm.vecs}")
vecs:
(array([-1.29289322, -2. , -2. , -2. ]), array([2.70710678, 2. , 2. , 2. ]))
calc_proj_ineq_constraint() function calculates the projection of Povm \(\{|\Pi_x\rangle\rangle\}_x\) on inequal constraint as follows:
For each \(x\), calculate the following:
Executes singular value decomposition on the elements of Povm \(\Pi_x\), \(\Pi_x = U \Lambda U^{\dagger}\), where \(\Lambda = \text{diag}[\lambda_0, \dots , \lambda_{d-1}]\), and \(\lambda_{i} \in \mathbb{R}\).
\(\lambda^{\prime}_{i} := \begin{cases} \lambda_{i} & (\lambda_{i} \geq 0) \\ 0 & (\lambda_{i} < 0) \end{cases}\)
\(\Lambda^{\prime} = \text{diag}[\lambda^{\prime}_0, \dots , \lambda^{\prime}_{d-1}]\)
\(\Pi_x^{\prime} = U \Lambda^{\prime} U^{\dagger}\)
The projection of Povm is \(\{|\Pi_x^{\prime} \rangle\rangle\}_x\).
[11]:
povm = Povm(c_sys, vecs, is_physicality_required=False)
proj_povm = povm.calc_proj_ineq_constraint()
print(f"vecs: \n{proj_povm.vecs}")
vecs:
(array([3.1925824 , 1.18569534, 1.77854301, 2.37139068]), array([8.60327781, 4.22884788, 4.93365586, 5.63846384]))
functions to transform parameters
to_stacked_vector() function returns a one-dimensional numpy array of all variables. This is equal to a concatenated vector of elements of vecs.
[12]:
print(f"to_stacked_vector(): {povm.to_stacked_vector()}")
print(f"vecs: \n{povm.vecs}")
to_stacked_vector(): [1. 2. 3. 4. 5. 6. 7. 8.]
vecs:
(array([1., 2., 3., 4.]), array([5., 6., 7., 8.]))
on_para_eq_constraint is True, then the last element of Povm \(\Pi_{m-1}\) is equal to \(I - \sum_{x=0}^{m-2} \Pi_x\). Thus, Povm is characterized by vecs[0],…, vecs[m-2].to_var() function returns a vector combining elements of of vecs[0],…, vecs[m-2], where on_para_eq_constraint is True.[13]:
vec1 = np.array([1, 0, 0, 1]) / np.sqrt(2)
vec2 = np.array([1, 0, 0, -1]) / np.sqrt(2)
vecs = [vec1, vec2]
[14]:
# on_para_eq_constraint=True
povm = Povm(c_sys, vecs, on_para_eq_constraint=True)
print(f"to_var(): {povm.to_var()}")
to_var(): [0.70710678 0. 0. 0.70710678]
[15]:
# on_para_eq_constraint=False
povm = Povm(c_sys, vecs, on_para_eq_constraint=False)
print(f"to_var(): {povm.to_var()}")
to_var(): [ 0.70710678 0. 0. 0.70710678 0.70710678 0. 0. -0.70710678]
functions to generate special objects
[16]:
zero_povm = povm.generate_zero_obj()
print(f"zero: \n{zero_povm.vecs}")
origin_povm = povm.generate_origin_obj()
print(f"origin: \n{origin_povm.vecs}")
zero:
(array([0., 0., 0., 0.]), array([0., 0., 0., 0.]))
origin:
(array([0.70710678, 0. , 0. , 0. ]), array([0.70710678, 0. , 0. , 0. ]))
supports arithmetic operations
[17]:
vec11 = np.array([1.0, 2.0, 3.0, 4.0])
vec12 = np.array([5.0, 6.0, 7.0, 8.0])
povm1 = Povm(c_sys, [vec11, vec12], is_physicality_required=False)
vec21 = np.array([9.0, 10.0, 11.0, 12.0])
vec22 = np.array([13.0, 14.0, 15.0, 16.0])
povm2 = Povm(c_sys, [vec21, vec22], is_physicality_required=False)
print(f"sum: \n{(povm1 + povm2).vecs}")
print(f"subtraction: \n{(povm1 - povm2).vecs}")
print(f"right multiplication: \n{(2 * povm1).vecs}")
print(f"left multiplication: \n{(povm1 * 2).vecs}")
print(f"division: \n{(povm1 / 2).vecs}")
sum:
(array([10., 12., 14., 16.]), array([18., 20., 22., 24.]))
subtraction:
(array([-8., -8., -8., -8.]), array([-8., -8., -8., -8.]))
right multiplication:
(array([2., 4., 6., 8.]), array([10., 12., 14., 16.]))
left multiplication:
(array([2., 4., 6., 8.]), array([10., 12., 14., 16.]))
division:
(array([0.5, 1. , 1.5, 2. ]), array([2.5, 3. , 3.5, 4. ]))
calc_gradient functions
Calculates gradient of Povm with variable index.
[18]:
grad_povm = povm.calc_gradient(0)
print(f"vecs: {grad_povm.vecs}")
vecs: (array([1., 0., 0., 0.]), array([0., 0., 0., 0.]))
convert_basis function
Returns vecs converted to the specified basis.
[19]:
from quara.objects.matrix_basis import get_comp_basis
povm = generate_povm_from_name("z", c_sys)
converted_vecs = povm.convert_basis(get_comp_basis())
print(f"vecs: {converted_vecs}")
vecs: [array([1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]), array([0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j])]
generate_mprocess function
Generates MProcess from this Povm.
[20]:
print(povm.generate_mprocess())
Type:
MProcess
Dim:
2
HSs:
[array([[0.5, 0. , 0. , 0.5],
[0. , 0. , 0. , 0. ],
[0. , 0. , 0. , 0. ],
[0.5, 0. , 0. , 0.5]]), array([[ 0.5, 0. , 0. , -0.5],
[ 0. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 0. ],
[-0.5, 0. , 0. , 0.5]])]
ModeSampling:
False
some utility functions
[21]:
print(f"vec(0): \n{povm.vec(0)}")
print(f"matrices(): \n{povm.matrices()}")
print(f"matrix(0): \n{povm.matrix(0)}")
print(f"is_hermitian(): \n{povm.is_hermitian()}")
print(f"is_positive_semidefinite(): \n{povm.is_positive_semidefinite()}")
print(f"is_identity_sum(): \n{povm.is_identity_sum()}")
print(f"calc_eigenvalues(): \n{povm.calc_eigenvalues()}")
vec(0):
[0.70710678 0. 0. 0.70710678]
matrices():
[matrix([[1.+0.j, 0.+0.j],
[0.+0.j, 0.+0.j]]), matrix([[0.+0.j, 0.+0.j],
[0.+0.j, 1.+0.j]])]
matrix(0):
[[1.+0.j 0.+0.j]
[0.+0.j 0.+0.j]]
is_hermitian():
True
is_positive_semidefinite():
True
is_identity_sum():
True
calc_eigenvalues():
[[0.9999999999999998, 0.0], [0.9999999999999998, 0.0]]
povm_typical
generate_povm_object_from_povm_name_object_name() function in povm_typical module can easily generate objects related to Povm.generate_povm_object_from_povm_name_object_name() function has the following arguments:The string that can be specified for
povm_namecan be checked by executing theget_povm_names()function. The tensor product of povm_name “a”, “b” is written “a_b”.object_namecan be the following string:“pure_state_vectors” - list of vector of pure states.
“matrices” - matrices of vector of pure states.
“vectors” - list of vectorized matrices.
“povm” - Povm object.
c_sys- CompositeSystem of objects related to Povm. Specify whenobject_nameis “povm”.basis- MatrixBasis of objects related to Povm. Specify whenobject_nameis “vectors”.is_physicality_required- Whether the generated object is physicality required, by default True.
[22]:
from quara.objects.povm_typical import (
get_povm_names,
generate_povm_object_from_povm_name_object_name,
)
#get_povm_names()
object_name = “pure_state_vectors”
[23]:
vecs = generate_povm_object_from_povm_name_object_name("z", "pure_state_vectors")
print(vecs)
[array([1.+0.j, 0.+0.j]), array([0.+0.j, 1.+0.j])]
object_name = “matrices”
[24]:
matrices = generate_povm_object_from_povm_name_object_name("z", "matrices")
print(matrices)
[array([[1.+0.j, 0.+0.j],
[0.+0.j, 0.+0.j]]), array([[0.+0.j, 0.+0.j],
[0.+0.j, 1.+0.j]])]
object_name = “vectors”
[25]:
basis = get_normalized_pauli_basis(1)
vectors = generate_povm_object_from_povm_name_object_name("z", "vectors", basis=basis)
print(vectors)
[array([0.70710678, 0. , 0. , 0.70710678]), array([ 0.70710678, 0. , 0. , -0.70710678])]
object_name = “povm”
[26]:
c_sys = generate_composite_system("qubit", 1)
povm = generate_povm_object_from_povm_name_object_name("z", "povm", c_sys=c_sys)
print(povm)
Type:
Povm
Dim:
2
Number of outcomes:
2
Vecs:
[[ 0.70710678 0. 0. 0.70710678]
[ 0.70710678 0. 0. -0.70710678]]