Download Notebook

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)}\)))

Then Lindbladian operator \(\mathcal{L}\) is defined by \(\mathcal{L}(\rho) = -i[H, \rho] + \{J, \rho\} + \sum_{\alpha, \beta=1}^{d^2-1} K_{\alpha, \beta} B_\alpha \rho B^{\dagger}_\beta\).
Let \(L^{cb}\) (resp. \(L^{gb}\)) be a Hilbert-Schmidt representation matrix of \(\mathcal{L}\) on computational basis (resp. on basis \(B\)).
We can write \(L^{cb} = -i(H \otimes I - I \otimes \bar{H}) + (J \otimes I + I \otimes \bar{J}) + \sum_{\alpha, \beta=1}^{d^2-1} K_{\alpha, \beta} B_\alpha \otimes \overline{B_\beta}\). And \(L^{gb} \in \mathbb{R}^{d^2 \times d^2}\).
The property hs of EffectiveLindbladian is a two-dimensional numpy array \(L^{gb}\) in Quara.
Also, there is a relationship \(G = e^L\), where \(G\) is a hs of Gate and \(e^L\) is a exponential of hs of EffectiveLindbladian.
The following terms are used in Quara:
  • \(-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.]
If 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.
Therefore, 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.
The generate_effective_lindbladian_object_from_gate_name_object_name() function has the following arguments:
  • The string that can be specified for gate_name can be checked by executing the get_gate_names() and get_gate_names_2qubit_asymmetric() function. The tensor product of state_name “a”, “b” is written “a_b”.

  • object_name can 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 when object_name is “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.        ]]

Download Notebook