EffectiveLindbladian and effective_lindbladian_typical
[1]:
import numpy as np
np.set_printoptions(linewidth=200)
EffectiveLindbladian
Assume the following situation:
\(B = \{ B_\alpha \}\) is a orthonormalized Hermitian matrix basis with \(B_0 = I/\sqrt{d}\), where \(d\) is dimension of CompositeSystem.
\(\rho\) is a density matrix.
\(H = \sum_{\alpha=1}^{d^2-1} H_\alpha B_\alpha\) (\(H_\alpha \in \mathbb{R}\), \(H \in \mathbb{C}^{d \times d}\)) : Hermitian matrix.
\(J = \sum_{\alpha=0}^{d^2-1} J_\alpha B_\alpha\) (\(J_\alpha \in \mathbb{R}\), \(J \in \mathbb{C}^{d \times d}\)) : Hermitian matrix.
\(K\) is a Hermitian and positive semidifinite matrix, with \((\alpha, \beta)\) entries are \(K_{\alpha, \beta}\). (\(K_{\alpha, \beta} \in \mathbb{R}\), \(K \in \mathbb{C}^{(d^2-1) \times (d^2-1)}\)))
hs of EffectiveLindbladian is a two-dimensional numpy array \(L^{gb}\) in Quara.hs of Gate and \(e^L\) is a exponential of hs of EffectiveLindbladian.\(-i(H \otimes I - I \otimes \bar{H})\) is called H-part.
\(J \otimes I + I \otimes \bar{J}\) is called J-part.
\(\sum_{\alpha, \beta=1}^{d^2-1} K_{\alpha, \beta} B_\alpha \otimes \overline{B_\beta}\) is called K-part.
The sum of J-part and K-part is called D-part.
EffectiveLindbladian class inherits Gate class in Quara.
Generate from effective_lindbladian_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.effective_lindbladian_typical import generate_effective_lindbladian_from_gate_name
c_sys = generate_composite_system("qubit", 1)
el = generate_effective_lindbladian_from_gate_name("x", c_sys)
print(el)
Type:
EffectiveLindbladian
Dim:
2
HS:
[[ 0. 0. 0. 0. ]
[ 0. 0. 0. 0. ]
[ 0. 0. 0. -3.14159265]
[ 0. 0. 3.14159265 0. ]]
Generate EffectiveLindbladian object directly using CompositeSystem and a 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.effective_lindbladian import EffectiveLindbladian
basis = get_normalized_pauli_basis(1)
e_sys = ElementalSystem(0, basis)
c_sys = CompositeSystem([e_sys])
hs = np.array([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, -np.pi], [0, 0, np.pi, 0]], dtype=np.float64)
el = EffectiveLindbladian(c_sys, hs)
print(el)
Type:
EffectiveLindbladian
Dim:
2
HS:
[[ 0. 0. 0. 0. ]
[ 0. 0. 0. 0. ]
[ 0. 0. 0. -3.14159265]
[ 0. 0. 3.14159265 0. ]]
specific properties
The property hs of EffectiveLindbladian is a 2-dimensional numpy array specified by the constructor argument hs
[4]:
el = EffectiveLindbladian(c_sys, hs)
print(f"hs: \n{el.hs}")
hs:
[[ 0. 0. 0. 0. ]
[ 0. 0. 0. 0. ]
[ 0. 0. 0. -3.14159265]
[ 0. 0. 3.14159265 0. ]]
The property dim of EffectiveLindbladian is the size of square matrix hs.
[5]:
print(f"dim: {el.dim}")
print(f"size of square matrix hs: {int(np.sqrt(hs.shape[0]))}")
dim: 2
size of square matrix hs: 2
functions to check constraints
The is_eq_constraint_satisfied() function returns True, if and only if \(e^L\) is TP(trace-preserving map), i.e. if and only if the first row of hs is zeros.
[6]:
print(f"is_eq_constraint_satisfied(): {el.is_eq_constraint_satisfied()}")
print(f"is_tp(): {el.is_tp()}")
print(f"hs[0]: {el.hs[0]}")
is_eq_constraint_satisfied(): True
is_tp(): True
hs[0]: [0. 0. 0. 0.]
The is_ineq_constraint_satisfied() function returns True, if and only if \(e^L\) is CP(Complete-Positivity-Preserving), i.e. if and only if K-part is positive semidifinite matrix.
[7]:
import quara.utils.matrix_util as mutil
print(f"is_eq_constraint_satisfied(): {el.is_eq_constraint_satisfied()}")
print(f"is_cp(): {el.is_cp()}")
print(f"is_positive_semidefinite(): {mutil.is_positive_semidefinite(el.calc_k_mat())}")
is_eq_constraint_satisfied(): True
is_cp(): True
is_positive_semidefinite(): True
projection functions
calc_proj_eq_constraint() function calculates the projection of EffectiveLindbladian on equal constraint. This function replaces the first row of hs with \([0,…,0]\).
[8]:
hs = np.array(range(16), dtype=np.float64).reshape((4, 4))
print(f"hs: \n{el.hs}")
hs:
[[ 0. 0. 0. 0. ]
[ 0. 0. 0. 0. ]
[ 0. 0. 0. -3.14159265]
[ 0. 0. 3.14159265 0. ]]
[9]:
el = EffectiveLindbladian(c_sys, hs, is_physicality_required=False)
proj_el = el.calc_proj_eq_constraint()
print(f"hs: \n{proj_el.hs}")
hs:
[[ 0. 0. 0. 0.]
[ 4. 5. 6. 7.]
[ 8. 9. 10. 11.]
[12. 13. 14. 15.]]
calc_proj_ineq_constraint() function calculates the projection of EffectiveLindbladian with hs on inequal constraint as follows:
Calculates H-part \(H\), J-part \(J\), and K-part \(K\) from EffectiveLindbladian.
Executes singular value decomposition on \(K\), \(K = 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}]\)
\(K^{\prime} = U \Lambda^{\prime} U^{\dagger}\)
Let \(\text{HS}^{\prime}\) be a Hilbert-Schmidt matrix representation of EffectiveLindbladian from \(H, J, K^{\prime}\).
The projection of EffectiveLindbladian is EffectiveLindbladian with
hs= \(\text{HS}^{\prime}\).
[10]:
el = EffectiveLindbladian(c_sys, hs, is_physicality_required=False)
proj_el = el.calc_proj_ineq_constraint()
print(f"hs: \n{proj_el.hs}")
hs:
[[ 8.12020183 1.71420693 5.06233752 7.16046811]
[ 0.78579307 -5.04434853 2.49719848 1.93917625]
[ 4.93766248 5.49719848 -2.88819756 4.92554488]
[ 7.83953189 7.93917625 7.92554488 -0.18765574]]
functions to transform parameters
to_stacked_vector() function returns a one-dimensional numpy array of all variables. This is equal to flattened hs.
[11]:
print(f"to_stacked_vector(): {el.to_stacked_vector()}")
print(f"flattened hs: {el.hs.flatten()}")
to_stacked_vector(): [ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15.]
flattened hs: [ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15.]
on_para_eq_constraint is True, then the first row of hs is equal to [0,…,0]. Thus, EffectiveLindbladian is characterized by the second and subsequent rows of hs.to_var() function returns the flattened second and subsequent rows of hs, where on_para_eq_constraint is True.[12]:
# on_para_eq_constraint=True
el = EffectiveLindbladian(c_sys, hs, is_physicality_required=False, on_para_eq_constraint=True)
print(f"to_var(): {el.to_var()}")
to_var(): [ 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15.]
[13]:
# on_para_eq_constraint=False
el = EffectiveLindbladian(c_sys, hs, is_physicality_required=False, on_para_eq_constraint=False)
print(f"to_var(): {el.to_var()}")
to_var(): [ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15.]
functions to generate special objects
[14]:
zero_el = el.generate_zero_obj()
print(f"zero: \n{zero_el.hs}")
origin_el = el.generate_origin_obj()
print(f"origin: \n{origin_el.hs}")
zero:
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
origin:
[[ 0. 0. 0. 0.]
[ 0. -1021. 0. 0.]
[ 0. 0. -1021. 0.]
[ 0. 0. 0. -1021.]]
supports arithmetic operations
[15]:
hs1 = np.array(range(16), dtype=np.float64).reshape((4, 4))
el1 = EffectiveLindbladian(c_sys, hs1, is_physicality_required=False)
hs2 = np.array(range(16, 32), dtype=np.float64).reshape((4, 4))
el2 = EffectiveLindbladian(c_sys, hs2, is_physicality_required=False)
print(el1.hs)
print(el2.hs)
[[ 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.]]
[16]:
print(f"sum: \n{(el1 + el2).hs}")
print(f"subtraction: \n{(el1 - el2).hs}")
print(f"right multiplication: \n{(2 * el1).hs}")
print(f"left multiplication: \n{(el1 * 2).hs}")
print(f"division: \n{(el1 / 2).hs}")
sum:
[[16. 18. 20. 22.]
[24. 26. 28. 30.]
[32. 34. 36. 38.]
[40. 42. 44. 46.]]
subtraction:
[[-16. -16. -16. -16.]
[-16. -16. -16. -16.]
[-16. -16. -16. -16.]
[-16. -16. -16. -16.]]
right multiplication:
[[ 0. 2. 4. 6.]
[ 8. 10. 12. 14.]
[16. 18. 20. 22.]
[24. 26. 28. 30.]]
left multiplication:
[[ 0. 2. 4. 6.]
[ 8. 10. 12. 14.]
[16. 18. 20. 22.]
[24. 26. 28. 30.]]
division:
[[0. 0.5 1. 1.5]
[2. 2.5 3. 3.5]
[4. 4.5 5. 5.5]
[6. 6.5 7. 7.5]]
calc_gradient functions
Calculates gradient of EffectiveLindbladian with variable index.
[17]:
grad_el = el.calc_gradient(0)
print(f"hs: \n{grad_el.hs}")
hs:
[[1. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
convert_basis function
Returns hs converted to the specified basis.
[18]:
from quara.objects.matrix_basis import get_comp_basis
el = generate_effective_lindbladian_from_gate_name("x", c_sys)
converted_hs = el.convert_basis(get_comp_basis())
print(f"hs: \n{converted_hs}")
hs:
[[0.+0.j 0.+1.57079633j 0.-1.57079633j 0.+0.j ]
[0.+1.57079633j 0.+0.j 0.+0.j 0.-1.57079633j]
[0.-1.57079633j 0.+0.j 0.+0.j 0.+1.57079633j]
[0.+0.j 0.-1.57079633j 0.+1.57079633j 0.+0.j ]]
calc_h_mat
Calculates the matrix \(H = \sum_{\alpha=1}^{d^2-1} H_\alpha B_\alpha\), with \(H_\alpha = \frac{i}{2d} \text{Tr}[L^{cb}(B_\alpha \otimes I - I \otimes \overline{B_\alpha})]\).
[19]:
el = generate_effective_lindbladian_from_gate_name("x", c_sys)
print(f"calc_h_mat(): \n{el.calc_h_mat()}")
calc_h_mat():
[[0. +0.j 1.57079633+0.j]
[1.57079633+0.j 0. +0.j]]
calc_j_mat
Calculates the matrix \(J = \sum_{\alpha=0}^{d^2-1} J_\alpha B_\alpha\), with \(J_\alpha = \frac{i}{2d(1 + \delta_{0,\alpha})} \text{Tr}[L^{cb}(B_\alpha \otimes I + I \otimes \overline{B_\alpha})]\).
[20]:
el = generate_effective_lindbladian_from_gate_name("x", c_sys)
print(f"calc_j_mat(): \n{el.calc_j_mat()}")
calc_j_mat():
[[0.+0.j 0.+0.j]
[0.+0.j 0.+0.j]]
calc_k_mat
Calculates the matrix \(K\), with \((\alpha, \beta)\) entry \(K_{\alpha, \beta} = \text{Tr}[L^{cb}(B_\alpha \otimes \overline{B_\beta})]\).
[21]:
el = generate_effective_lindbladian_from_gate_name("x", c_sys)
print(f"calc_k_mat(): \n{el.calc_k_mat()}")
calc_k_mat():
[[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]]
calc_h_part
Calculates H-part = \(-i(H \otimes I - I \otimes \bar{H})\).
[22]:
el = generate_effective_lindbladian_from_gate_name("x", c_sys)
print(f"calc_h_part(): \n{el.calc_h_part()}")
calc_h_part():
[[ 0. 0. 0. 0. ]
[ 0. 0. 0. 0. ]
[ 0. 0. 0. -3.14159265]
[ 0. 0. 3.14159265 0. ]]
calc_j_part
Calculates J-part = \(J \otimes I + I \otimes \bar{J}\).
[23]:
el = generate_effective_lindbladian_from_gate_name("x", c_sys)
print(f"calc_j_part(): \n{el.calc_j_part()}")
calc_j_part():
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
calc_k_part
Calculates K-part = \(\sum_{\alpha, \beta=1}^{d^2-1} K_{\alpha, \beta} B_\alpha \otimes \overline{B_\beta}\)
[24]:
el = generate_effective_lindbladian_from_gate_name("x", c_sys)
print(f"calc_k_part(): \n{el.calc_k_part()}")
calc_k_part():
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
calc_d_part
Calculates D-part = J-part + K-part
[25]:
el = generate_effective_lindbladian_from_gate_name("x", c_sys)
print(f"calc_d_part(): \n{el.calc_d_part()}")
calc_d_part():
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
to_kraus_matrices
Returns Kraus matrices of EffectiveLindbladian.
[26]:
el = generate_effective_lindbladian_from_gate_name("x", c_sys)
print(f"to_kraus_matrices(): \n{el.to_kraus_matrices()}")
to_kraus_matrices():
[((1.7724538509055159-4.030482324789019e-33j), array([[ 5.00000000e-01+0.j , -2.01094314e-17-0.5j],
[ 2.01094314e-17-0.5j, 5.00000000e-01+0.j ]])), ((4.0304823506953305e-33+1.7724538509055157j), array([[ 5.00000000e-01+0.00000000e+00j, 2.01094314e-17+5.00000000e-01j],
[-2.01094314e-17+5.00000000e-01j, 5.00000000e-01+1.54074396e-33j]]))]
to_gate
Generates Gate from EffectiveLindbladian.
[27]:
el = generate_effective_lindbladian_from_gate_name("x", c_sys)
print(el.to_gate())
Type:
Gate
Dim:
2
HS:
[[ 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00]
[ 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00]
[-0.00000000e+00 -0.00000000e+00 -1.00000000e+00 -2.35127499e-16]
[ 0.00000000e+00 0.00000000e+00 2.35127499e-16 -1.00000000e+00]]
some utility functions
[28]:
print(f"is_tp(): {el.is_tp()}")
print(f"is_cp(): {el.is_cp()}")
is_tp(): True
is_cp(): True
effective_lindbladian_typical
generate_effective_lindbladian_object_from_gate_name_object_name() function in effective_lindbladian_typical module can easily generate objects related to State.generate_effective_lindbladian_object_from_gate_name_object_name() function has the following arguments:The string that can be specified for
gate_namecan be checked by executing theget_gate_names()andget_gate_names_2qubit_asymmetric()function. The tensor product of state_name “a”, “b” is written “a_b”.object_namecan be the following string:“hamiltonian_vec” - the vector representation of the Hamiltonian of a gate.
“hamiltonian_mat” - the Hamiltonian matrix of a gate.
“effective_lindbladian_mat” - the Hilbert-Schmidt representation matrix of an effective lindbladian.
“effective_lindbladian” - EffectiveLindbladian object.
c_sys- CompositeSystem of objects related to EffectiveLindbladian. Specify whenobject_nameis “effective_lindbladian”.is_physicality_required- Whether the generated object is physicality required, by default True.
[29]:
from quara.objects.gate_typical import (
get_gate_names,
get_gate_names_2qubit_asymmetric,
)
from quara.objects.effective_lindbladian_typical import generate_effective_lindbladian_object_from_gate_name_object_name
#get_gate_names()
#get_gate_names_2qubit_asymmetric()
object_name = “hamiltonian_vec”
[30]:
vec = generate_effective_lindbladian_object_from_gate_name_object_name("x", "hamiltonian_vec")
print(vec)
[-2.22144147 2.22144147 0. 0. ]
object_name = “hamiltonian_mat”
[31]:
mat = generate_effective_lindbladian_object_from_gate_name_object_name("x", "hamiltonian_mat")
print(mat)
[[-1.57079633+0.j 1.57079633+0.j]
[ 1.57079633+0.j -1.57079633+0.j]]
object_name = “effective_lindbladian_mat”
[32]:
mat = generate_effective_lindbladian_object_from_gate_name_object_name("x", "effective_lindbladian_mat")
print(mat)
[[ 0. 0. 0. 0. ]
[ 0. 0. 0. 0. ]
[ 0. 0. 0. -3.14159265]
[ 0. 0. 3.14159265 0. ]]
object_name = “effective_lindbladian”
[33]:
c_sys = generate_composite_system("qubit", 1)
el = generate_effective_lindbladian_object_from_gate_name_object_name("x", "effective_lindbladian", c_sys=c_sys)
print(el)
Type:
EffectiveLindbladian
Dim:
2
HS:
[[ 0. 0. 0. 0. ]
[ 0. 0. 0. 0. ]
[ 0. 0. 0. -3.14159265]
[ 0. 0. 3.14159265 0. ]]