Skip to content

Commit 7ded018

Browse files
committed
add generaldepolarizingchannel
1 parent 41f0254 commit 7ded018

File tree

3 files changed

+164
-5
lines changed

3 files changed

+164
-5
lines changed

tensorcircuit/channels.py

+136-5
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
"""
44

55
import sys
6-
from typing import Any, Sequence
6+
from typing import Any, Sequence, Optional, Union
7+
from operator import and_
8+
from functools import reduce
79

810
import numpy as np
911

@@ -78,6 +80,128 @@ def depolarizingchannel(px: float, py: float, pz: float) -> Sequence[Gate]:
7880
return [i, x, y, z]
7981

8082

83+
def generaldepolarizingchannel(
84+
p: Union[float, Sequence[Any]], num_qubits: int = 1
85+
) -> Sequence[Gate]:
86+
"""Return a Depolarizing Channel
87+
88+
.. math::
89+
\sqrt{1-p_x-p_y-p_z}
90+
\begin{bmatrix}
91+
1 & 0\\
92+
0 & 1\\
93+
\end{bmatrix}\qquad
94+
\sqrt{p_x}
95+
\begin{bmatrix}
96+
0 & 1\\
97+
1 & 0\\
98+
\end{bmatrix}\qquad
99+
\sqrt{p_y}
100+
\begin{bmatrix}
101+
0 & -1j\\
102+
1j & 0\\
103+
\end{bmatrix}\qquad
104+
\sqrt{p_z}
105+
\begin{bmatrix}
106+
1 & 0\\
107+
0 & -1\\
108+
\end{bmatrix}
109+
110+
:Example:
111+
112+
>>> cs=tc.channels.generaldepolarizingchannel([0.1,0.1,0.1],1)
113+
>>> tc.channels.kraus_identity_check(cs)
114+
>>> cs = tc.channels.generaldepolarizingchannel(0.02,2)
115+
>>> tc.channels.kraus_identity_check(cs)
116+
117+
118+
:param p: parameter for each Pauli channel
119+
:type p: Union[float, Sequence]
120+
:param num_qubits: number of qubits, defaults to 1
121+
:type num_qubits: int, optional
122+
:return: Sequences of Gates
123+
:rtype: Sequence[Gate]
124+
"""
125+
126+
if num_qubits == 1:
127+
128+
if isinstance(p, float):
129+
130+
assert p > 0 and p < 1 / 3, "p should be >0 and <1/3"
131+
probs = [1 - 3 * p] + 3 * [p]
132+
133+
elif isinstance(p, list):
134+
135+
assert reduce(
136+
and_, [pi > 0 and pi < 1 for pi in p]
137+
), "p should be >0 and <1"
138+
probs = [1 - sum(p)] + p # type: ignore
139+
140+
elif isinstance(p, tuple):
141+
142+
p = list[p] # type: ignore
143+
assert reduce(
144+
and_, [pi > 0 and pi < 1 for pi in p]
145+
), "p should be >0 and <1"
146+
probs = [1 - sum(p)] + p # type: ignore
147+
148+
else:
149+
raise ValueError("p should be float or list")
150+
151+
elif num_qubits == 2:
152+
153+
if isinstance(p, float):
154+
155+
assert p > 0 and p < 1, "p should be >0 and <1/15"
156+
probs = [1 - 15 * p] + 15 * [p]
157+
158+
elif isinstance(p, list):
159+
160+
assert reduce(
161+
and_, [pi > 0 and pi < 1 for pi in p]
162+
), "p should be >0 and <1"
163+
probs = [1 - sum(p)] + p # type: ignore
164+
165+
elif isinstance(p, tuple):
166+
167+
p = list[p] # type: ignore
168+
assert reduce(
169+
and_, [pi > 0 and pi < 1 for pi in p]
170+
), "p should be >0 and <1"
171+
probs = [1 - sum(p)] + p # type: ignore
172+
173+
else:
174+
raise ValueError("p should be float or list")
175+
176+
if num_qubits == 1:
177+
tup = [gates.i().tensor, gates.x().tensor, gates.y().tensor, gates.z().tensor] # type: ignore
178+
if num_qubits == 2:
179+
tup = [
180+
gates.ii().tensor, # type: ignore
181+
gates.ix().tensor, # type: ignore
182+
gates.iy().tensor, # type: ignore
183+
gates.iz().tensor, # type: ignore
184+
gates.xi().tensor, # type: ignore
185+
gates.xx().tensor, # type: ignore
186+
gates.xy().tensor, # type: ignore
187+
gates.xz().tensor, # type: ignore
188+
gates.yi().tensor, # type: ignore
189+
gates.yx().tensor, # type: ignore
190+
gates.yy().tensor, # type: ignore
191+
gates.yz().tensor, # type: ignore
192+
gates.zi().tensor, # type: ignore
193+
gates.zx().tensor, # type: ignore
194+
gates.zy().tensor, # type: ignore
195+
gates.zz().tensor, # type: ignore
196+
]
197+
198+
Gkarus = []
199+
for pro, paugate in zip(probs, tup):
200+
Gkarus.append(Gate(_sqrt(pro) * paugate))
201+
202+
return Gkarus
203+
204+
81205
def amplitudedampingchannel(gamma: float, p: float) -> Sequence[Gate]:
82206
r"""
83207
Return an amplitude damping channel.
@@ -187,25 +311,32 @@ def phasedampingchannel(gamma: float) -> Sequence[Gate]:
187311
return [m0, m1]
188312

189313

190-
def single_qubit_kraus_identity_check(kraus: Sequence[Gate]) -> None:
314+
def kraus_identity_check(kraus: Sequence[Gate]) -> None:
191315
r"""Check identity of a single qubit Kraus operators.
192316
193317
:Examples:
194318
195319
>>> cs = resetchannel()
196-
>>> tc.channels.single_qubit_kraus_identity_check(cs)
320+
>>> tc.channels.kraus_identity_check(cs)
197321
198322
.. math::
199323
\sum_{k}^{} K_k^{\dagger} K_k = I
200324
201325
:param kraus: List of Kraus operators.
202326
:type kraus: Sequence[Gate]
203327
"""
204-
placeholder = backend.zeros([2, 2])
328+
329+
dim = backend.shape_tuple(kraus[0].tensor)
330+
shape = (len(dim), len(dim))
331+
placeholder = backend.zeros(shape)
205332
placeholder = backend.cast(placeholder, dtype=cons.dtypestr)
206333
for k in kraus:
334+
k = Gate(backend.reshape(k.tensor, [len(dim), len(dim)]))
207335
placeholder += backend.conj(backend.transpose(k.tensor, [1, 0])) @ k.tensor
208-
np.testing.assert_allclose(placeholder, np.eye(2), atol=1e-5)
336+
np.testing.assert_allclose(placeholder, np.eye(shape[0]), atol=1e-5)
337+
338+
339+
single_qubit_kraus_identity_check = kraus_identity_check # backward compatibility
209340

210341

211342
def kraus_to_super_gate(kraus_list: Sequence[Gate]) -> Tensor:

tensorcircuit/gates.py

+15
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,21 @@
4747
_yy_matrix = np.kron(_y_matrix, _y_matrix)
4848
_zz_matrix = np.kron(_z_matrix, _z_matrix)
4949

50+
_ix_matrix = np.kron(_i_matrix, _x_matrix)
51+
_iy_matrix = np.kron(_i_matrix, _y_matrix)
52+
_iz_matrix = np.kron(_i_matrix, _z_matrix)
53+
_xi_matrix = np.kron(_x_matrix, _i_matrix)
54+
_yi_matrix = np.kron(_y_matrix, _i_matrix)
55+
_zi_matrix = np.kron(_z_matrix, _i_matrix)
56+
57+
_xy_matrix = np.kron(_x_matrix, _y_matrix)
58+
_xz_matrix = np.kron(_x_matrix, _z_matrix)
59+
_yx_matrix = np.kron(_y_matrix, _x_matrix)
60+
_yz_matrix = np.kron(_y_matrix, _z_matrix)
61+
_zx_matrix = np.kron(_z_matrix, _x_matrix)
62+
_zy_matrix = np.kron(_z_matrix, _y_matrix)
63+
64+
5065
_cnot_matrix = np.array(
5166
[
5267
[1.0, 0.0, 0.0, 0.0],

tests/test_dmcircuit.py

+13
Original file line numberDiff line numberDiff line change
@@ -256,3 +256,16 @@ def r(key):
256256
rs1, rs2 = r(key1), r(key2)
257257
assert rs1[0] != rs2[0]
258258
assert np.allclose(rs1[1], 0.4, atol=1e-5) or np.allclose(rs2[1], 0.4, atol=1e-5)
259+
260+
261+
@pytest.mark.parametrize("backend", [lf("npb"), lf("tfb"), lf("jaxb")])
262+
def test_dep(backend):
263+
264+
cs = tc.channels.generaldepolarizingchannel(0.1, 1)
265+
tc.channels.kraus_identity_check(cs)
266+
267+
cs = tc.channels.generaldepolarizingchannel([0.1, 0.1, 0.1], 1)
268+
tc.channels.kraus_identity_check(cs)
269+
270+
cs = tc.channels.generaldepolarizingchannel(0.02, 2)
271+
tc.channels.kraus_identity_check(cs)

0 commit comments

Comments
 (0)