MProcess and mprocess_typical
[1]:
import numpy as np
np.set_printoptions(linewidth=200)
MProcess (Measurement Process)
hss in Quara. hss is a list of 2-dimensional numpy array.mode_sampling of MProcess is whether to sample to determine one Hilbert-Schumidt matrix with compose_qoperations() function.random_seed_or_generator of MProcess is the random seed or numpy.random.Generator to sample.Generate from mprocess_typical module by specifying CompositeSystem and state mprocess (ex. “z-type1”).
[2]:
from quara.objects.composite_system_typical import generate_composite_system
from quara.objects.mprocess_typical import generate_mprocess_from_name
c_sys = generate_composite_system("qubit", 1)
mprocess = generate_mprocess_from_name(c_sys, "z-type1")
print(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
Generate MProcess object directly using CompositeSystem and a numpy array.
[3]:
import numpy as np
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.mprocess import MProcess
basis = get_normalized_pauli_basis(1)
e_sys = ElementalSystem(0, basis)
c_sys = CompositeSystem([e_sys])
hss = [
np.array([[0.5, 0, 0, 0.5], [0, 0, 0, 0], [0, 0, 0, 0], [0.5, 0, 0, 0.5]]),
np.array([[0.5, 0, 0, -0.5], [0, 0, 0, 0], [0, 0, 0, 0], [-0.5, 0, 0, 0.5]]),
]
mprocess = MProcess(c_sys, hss)
print(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
specific properties
The property hss of MProcess is a numpy array specified by the constructor argument hss.
[4]:
mprocess = MProcess(c_sys, hss)
print(f"hss: \n{mprocess.hss}")
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]])]
The hs() function returns a numpy array specified by the constructor argument hss.
[5]:
mprocess = MProcess(c_sys, hss)
print(f"hs(0): \n{mprocess.hs(0)}")
print(f"hs(1): \n{mprocess.hs(1)}")
hs(0):
[[0.5 0. 0. 0.5]
[0. 0. 0. 0. ]
[0. 0. 0. 0. ]
[0.5 0. 0. 0.5]]
hs(1):
[[ 0.5 0. 0. -0.5]
[ 0. 0. 0. 0. ]
[ 0. 0. 0. 0. ]
[-0.5 0. 0. 0.5]]
The property dim of MProcess is the size of square matrices hss.
[6]:
print(f"dim: {mprocess.dim}")
print(f"size of square matrices hss: {int(np.sqrt(hss[0].shape[0]))}")
dim: 2
size of square matrices hss: 2
The property num_outcomes of MProcess is the number of hss.
[7]:
print(f"num_outcomes: {mprocess.num_outcomes}")
print(f"number of hss: {len(mprocess.hss)}")
num_outcomes: 2
number of hss: 2
The property mode_sampling of MProcess is the mode of sampling.
[8]:
print(mprocess.mode_sampling)
False
functions to check constraints
The is_eq_constraint_satisfied() function returns True, if and only if the sum of hss is TP(trace-preserving map).
[9]:
print(f"is_eq_constraint_satisfied(): {mprocess.is_eq_constraint_satisfied()}")
print(f"is_sum_tp(): {mprocess.is_sum_tp()}")
is_eq_constraint_satisfied(): True
is_sum_tp(): True
The is_ineq_constraint_satisfied() function returns True, if and only if all matrices of hss are CP(Complete-Positivity-Preserving), i.e. if and only if all Choi matrices of hss are positive semidifinite matrices.
[10]:
print(f"is_ineq_constraint_satisfied(): {mprocess.is_ineq_constraint_satisfied()}")
print(f"is_cp(): {mprocess.is_cp()}")
is_ineq_constraint_satisfied(): True
is_cp(): True
projection functions
calc_proj_eq_constraint() function calculates the projection of MProcess on equal constraint. Let hss of MProcess be \(\{ M_0, \dots, M_{m-1}\}\), where \(m\) is num_outcomes of MProcess. When MProcess object satifies on equal constraint, the first row of \(\sum_{x=0}^{m-1} M_x\) is equal to \([1, 0, \dots, 0]\).calc_proj_eq_constraint() function calculates the projection of MProcess as follows:\(\text{vec} :=\) the first row of \(\sum_{x=0}^{m-1} M_x\)
for each \(x\), calculates \(M^{\prime}_x = M_x - \frac{1}{m}\begin{bmatrix} \text{vec} \\ 0 \\ \vdots \\ 0 \end{bmatrix} + \frac{1}{m}\begin{bmatrix} 1 & 0 & \dots & 0 \\ 0 \\ \vdots & & \huge{0} \\ 0 \end{bmatrix}\)
The projection of MProcess is \(\{ M^{\prime}_x \}_{x=0}^{m-1}\).
[11]:
hss = [
np.array(range(16), dtype=np.float64).reshape((4, 4)),
np.array(range(16, 32), dtype=np.float64).reshape((4, 4)),
]
[12]:
mprocess = MProcess(c_sys, hss, is_physicality_required=False)
proj_mprocess = mprocess.calc_proj_eq_constraint()
print(f"hss: \n{proj_mprocess.hss}")
hss:
[array([[-7.5, -8. , -8. , -8. ],
[ 4. , 5. , 6. , 7. ],
[ 8. , 9. , 10. , 11. ],
[12. , 13. , 14. , 15. ]]), array([[ 8.5, 8. , 8. , 8. ],
[20. , 21. , 22. , 23. ],
[24. , 25. , 26. , 27. ],
[28. , 29. , 30. , 31. ]])]
calc_proj_ineq_constraint() function calculates the projection of MProcess with hss \(\{ M_x \}_{x=0}^{m-1}\) on inequal constraint as follows:
For each \(x\), calculate the following:
Let \(\text{Choi}_x\) be Choi matrix of \(M_x\)
Executes singular value decomposition on \(\text{Choi}_x\), \(\text{Choi}_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}]\)
\(\text{Choi}^{\prime}_x = U \Lambda^{\prime} U^{\dagger}\)
Let \(M^{\prime}_x\) be Hilbert-Schmidt matrix representation of \(\text{Choi}^{\prime}_x\)
The projection of MProcess is \(\{ M^{\prime}_x \}_{x=0}^{m-1}\).
[13]:
mprocess = MProcess(c_sys, hss, is_physicality_required=False)
proj_mprocess = mprocess.calc_proj_ineq_constraint()
print(f"hss: \n{proj_mprocess.hss}")
hss:
[array([[15.84558996, 4.43570942, 5.29265833, 6.14960724],
[ 2.63097854, 2.34702553, 3.08437192, 3.44443746],
[ 4.98440409, 4.50900796, 4.73510284, 5.71575945],
[ 7.33782964, 6.29370952, 7.14039548, 7.60980059]]), array([[47.32687829, 20.14755601, 21.1037168 , 22.0598776 ],
[17.5667235 , 12.54854821, 13.24883203, 13.79656536],
[20.93808076, 15.04184745, 15.53818711, 16.33962776],
[24.30943803, 17.3825962 , 18.13264319, 18.73013967]])]
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 flattened matrices of hss.
[14]:
print(f"to_stacked_vector(): \n{mprocess.to_stacked_vector()}")
print(f"hss: \n{mprocess.hss}")
to_stacked_vector():
[ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31.]
hss:
[array([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[12., 13., 14., 15.]]), array([[16., 17., 18., 19.],
[20., 21., 22., 23.],
[24., 25., 26., 27.],
[28., 29., 30., 31.]])]
hss of MProcess be \(\{ M_0, \dots, M_{m-1}\}\), where \(m\) is num_outcomes of MProcess. Let \(\text{vec}(M_x) := |M_x\rangle\rangle\). Let $:nbsphinx-math:text{vec}`(:nbsphinx-math:tilde{M}`_x) $ be a flattened vector of the second and subsequent rows of matrix \(M_x\).on_para_eq_constraint is True, then the first row of \(\sum_{x=0}^{m-1} M_x\) is equal to \([1, 0, \dots, 0]\).to_var() function returns a concatenated vector of \(\text{vec}(M_0), \dots, \text{vec}(M_{m-2}), \text{vec}(\tilde{M}_{m-1})\), where on_para_eq_constraint is True.[15]:
# on_para_eq_constraint=True
mprocess = MProcess(c_sys, hss, is_physicality_required=False, on_para_eq_constraint=True)
print(f"to_var(): \n{mprocess.to_var()}")
to_var():
[ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31.]
[16]:
# on_para_eq_constraint=False
mprocess = MProcess(c_sys, hss, is_physicality_required=False, on_para_eq_constraint=False)
print(f"to_var(): \n{mprocess.to_var()}")
to_var():
[ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31.]
functions to generate special objects
[17]:
zero_mprocess = mprocess.generate_zero_obj()
print(f"zero: \n{zero_mprocess.hss}")
origin_mprocess = mprocess.generate_origin_obj()
print(f"origin: \n{origin_mprocess.hss}")
zero:
[array([[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]]), array([[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]])]
origin:
[array([[0.5, 0. , 0. , 0. ],
[0. , 0. , 0. , 0. ],
[0. , 0. , 0. , 0. ],
[0. , 0. , 0. , 0. ]]), array([[0.5, 0. , 0. , 0. ],
[0. , 0. , 0. , 0. ],
[0. , 0. , 0. , 0. ],
[0. , 0. , 0. , 0. ]])]
supports arithmetic operations
[18]:
hs11 = np.array(range(16), dtype=np.float64).reshape((4, 4))
hs12 = np.array(range(16, 32), dtype=np.float64).reshape((4, 4))
mprocess1 = MProcess(c_sys, [hs11, hs12], is_physicality_required=False)
hs21 = np.array(range(32, 48), dtype=np.float64).reshape((4, 4))
hs22 = np.array(range(48, 64), dtype=np.float64).reshape((4, 4))
mprocess2 = MProcess(c_sys, [hs21, hs22], is_physicality_required=False)
print(mprocess1.hss)
print(mprocess2.hss)
[array([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[12., 13., 14., 15.]]), array([[16., 17., 18., 19.],
[20., 21., 22., 23.],
[24., 25., 26., 27.],
[28., 29., 30., 31.]])]
[array([[32., 33., 34., 35.],
[36., 37., 38., 39.],
[40., 41., 42., 43.],
[44., 45., 46., 47.]]), array([[48., 49., 50., 51.],
[52., 53., 54., 55.],
[56., 57., 58., 59.],
[60., 61., 62., 63.]])]
[19]:
print(f"sum: \n{(mprocess1 + mprocess2).hss}")
print(f"subtraction: \n{(mprocess1 - mprocess2).hss}")
print(f"right multiplication: \n{(2 * mprocess1).hss}")
print(f"left multiplication: \n{(mprocess1 * 2).hss}")
print(f"division: \n{(mprocess1 / 2).hss}")
sum:
[array([[32., 34., 36., 38.],
[40., 42., 44., 46.],
[48., 50., 52., 54.],
[56., 58., 60., 62.]]), array([[64., 66., 68., 70.],
[72., 74., 76., 78.],
[80., 82., 84., 86.],
[88., 90., 92., 94.]])]
subtraction:
[array([[-32., -32., -32., -32.],
[-32., -32., -32., -32.],
[-32., -32., -32., -32.],
[-32., -32., -32., -32.]]), array([[-32., -32., -32., -32.],
[-32., -32., -32., -32.],
[-32., -32., -32., -32.],
[-32., -32., -32., -32.]])]
right multiplication:
[array([[ 0., 2., 4., 6.],
[ 8., 10., 12., 14.],
[16., 18., 20., 22.],
[24., 26., 28., 30.]]), array([[32., 34., 36., 38.],
[40., 42., 44., 46.],
[48., 50., 52., 54.],
[56., 58., 60., 62.]])]
left multiplication:
[array([[ 0., 2., 4., 6.],
[ 8., 10., 12., 14.],
[16., 18., 20., 22.],
[24., 26., 28., 30.]]), array([[32., 34., 36., 38.],
[40., 42., 44., 46.],
[48., 50., 52., 54.],
[56., 58., 60., 62.]])]
division:
[array([[0. , 0.5, 1. , 1.5],
[2. , 2.5, 3. , 3.5],
[4. , 4.5, 5. , 5.5],
[6. , 6.5, 7. , 7.5]]), array([[ 8. , 8.5, 9. , 9.5],
[10. , 10.5, 11. , 11.5],
[12. , 12.5, 13. , 13.5],
[14. , 14.5, 15. , 15.5]])]
calc_gradient functions
Calculates gradient of MProcess with variable index.
[20]:
grad_mprocess = mprocess.calc_gradient(0)
print(f"hss: \n{grad_mprocess.hss}")
hss:
[array([[1., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]]), array([[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]])]
convert_basis function
Returns hss converted to the specified basis.
[21]:
from quara.objects.matrix_basis import get_comp_basis
mprocess = generate_mprocess_from_name(c_sys, "z-type1")
converted_hss = mprocess.convert_basis(get_comp_basis())
print(f"hss: \n{converted_hss}")
hss:
[array([[1.00000000e+00+0.j, 0.00000000e+00+0.j, 0.00000000e+00+0.j, 6.22328532e-19+0.j],
[0.00000000e+00+0.j, 0.00000000e+00+0.j, 0.00000000e+00+0.j, 0.00000000e+00+0.j],
[0.00000000e+00+0.j, 0.00000000e+00+0.j, 0.00000000e+00+0.j, 0.00000000e+00+0.j],
[3.25176795e-17+0.j, 0.00000000e+00+0.j, 0.00000000e+00+0.j, 5.97792087e-34+0.j]]), array([[5.97792087e-34+0.j, 0.00000000e+00+0.j, 0.00000000e+00+0.j, 3.25176795e-17+0.j],
[0.00000000e+00+0.j, 0.00000000e+00+0.j, 0.00000000e+00+0.j, 0.00000000e+00+0.j],
[0.00000000e+00+0.j, 0.00000000e+00+0.j, 0.00000000e+00+0.j, 0.00000000e+00+0.j],
[6.22328532e-19+0.j, 0.00000000e+00+0.j, 0.00000000e+00+0.j, 1.00000000e+00+0.j]])]
to_choi_matrix
Returns Choi matrix of the specified index of hss.
[22]:
mprocess = generate_mprocess_from_name(c_sys, "z-type1")
print(f"to_choi_matrix(0): \n{mprocess.to_choi_matrix(0)}")
print(f"to_choi_matrix_with_dict(0): \n{mprocess.to_choi_matrix_with_dict(0)}")
print(f"to_choi_matrix(0): \n{mprocess.to_choi_matrix(0)}")
to_choi_matrix(0):
[[1.+0.j 0.+0.j 0.+0.j 0.+0.j]
[0.+0.j 0.+0.j 0.+0.j 0.+0.j]
[0.+0.j 0.+0.j 0.+0.j 0.+0.j]
[0.+0.j 0.+0.j 0.+0.j 0.+0.j]]
to_choi_matrix_with_dict(0):
[[1.+0.j 0.+0.j 0.+0.j 0.+0.j]
[0.+0.j 0.+0.j 0.+0.j 0.+0.j]
[0.+0.j 0.+0.j 0.+0.j 0.+0.j]
[0.+0.j 0.+0.j 0.+0.j 0.+0.j]]
to_choi_matrix(0):
[[1.+0.j 0.+0.j 0.+0.j 0.+0.j]
[0.+0.j 0.+0.j 0.+0.j 0.+0.j]
[0.+0.j 0.+0.j 0.+0.j 0.+0.j]
[0.+0.j 0.+0.j 0.+0.j 0.+0.j]]
to_kraus_matrices
Returns Kraus matrices of the specified index of hss.
[23]:
mprocess = generate_mprocess_from_name(c_sys, "z-type1")
print(f"to_kraus_matrices(0): \n{mprocess.to_kraus_matrices(0)}")
to_kraus_matrices(0):
[array([[1.+0.j, 0.+0.j],
[0.+0.j, 0.+0.j]])]
to_process_matrix
Returns process matrix of the specified index of hss.
[24]:
mprocess = generate_mprocess_from_name(c_sys, "z-type1")
print(f"to_process_matrix(0): \n{mprocess.to_process_matrix(0)}")
to_process_matrix(0):
[[1.00000000e+00+0.j 0.00000000e+00+0.j 0.00000000e+00+0.j 0.00000000e+00+0.j]
[0.00000000e+00+0.j 6.22328532e-19+0.j 0.00000000e+00+0.j 0.00000000e+00+0.j]
[0.00000000e+00+0.j 0.00000000e+00+0.j 3.25176795e-17+0.j 0.00000000e+00+0.j]
[0.00000000e+00+0.j 0.00000000e+00+0.j 0.00000000e+00+0.j 5.97792087e-34+0.j]]
to_povm
Generates Povm from MProcess.
[25]:
mprocess = generate_mprocess_from_name(c_sys, "z-type1")
print(mprocess.to_povm())
Type:
Povm
Dim:
2
Number of outcomes:
2
Vecs:
[[ 0.70710678 0. 0. 0.70710678]
[ 0.70710678 0. 0. -0.70710678]]
some utility functions
[26]:
print(f"is_sum_tp(): {mprocess.is_sum_tp()}")
print(f"is_cp(): {mprocess.is_cp()}")
is_sum_tp(): True
is_cp(): True
mprocess_typical
generate_mprocess_object_from_mprocess_name_object_name() function in mprocess_typical module can easily generate objects related to MProcess.generate_mprocess_object_from_mprocess_name_object_name() function has the following arguments:The string that can be specified for
mprocess_namecan be checked by executing theget_mprocess_names_type1()andget_mprocess_names_type2()functions. The tensor product of state_name “a”, “b” is written “a_b”.object_namecan be the following string:“set_pure_state_vectors” - The set of pure state vectors of MProcess.
“set_kraus_matrices” - The set of Kraus matrices of MProcess.
“hss” - The list of Hilbert-Schmidt matrix representations of MProcess.
“mprocess” - MProcess object.
c_sys- CompositeSystem of objects related to MProcess. Specify whenobject_nameis “hss” and “mprocess”.is_physicality_required- Whether the generated object is physicality required, by default True.
[27]:
from quara.objects.mprocess_typical import (
get_mprocess_names_type1,
get_mprocess_names_type2,
generate_mprocess_object_from_mprocess_name_object_name,
)
print(f"get_mprocess_names_type1(): \n{get_mprocess_names_type1()}")
print(f"get_mprocess_names_type2(): \n{get_mprocess_names_type2()}")
get_mprocess_names_type1():
['x-type1', 'y-type1', 'z-type1', 'bell-type1', 'z3-type1', 'z2-type1', 'xxparity-type1', 'zzparity-type1']
get_mprocess_names_type2():
['x-type2', 'y-type2', 'z-type2', 'z3-type2', 'z2-type2']
object_name = “set_pure_state_vectors”
[28]:
vecs = generate_mprocess_object_from_mprocess_name_object_name("z-type1", "set_pure_state_vectors")
print(vecs)
[[array([1.+0.j, 0.+0.j])], [array([0.+0.j, 1.+0.j])]]
object_name = “set_kraus_matrices”
[29]:
matrices = generate_mprocess_object_from_mprocess_name_object_name("z-type1", "set_kraus_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 = “hss”
[30]:
c_sys = generate_composite_system("qubit", 1)
hss = generate_mprocess_object_from_mprocess_name_object_name("z-type1", "hss", c_sys=c_sys)
print(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]])]
object_name = “mprocess”
[31]:
c_sys = generate_composite_system("qubit", 1)
mprocess = generate_mprocess_object_from_mprocess_name_object_name("z-type1", "mprocess", c_sys=c_sys)
print(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