Skip to content

Commit a586878

Browse files
committed
revise noise model
1 parent a21dc68 commit a586878

File tree

2 files changed

+95
-52
lines changed

2 files changed

+95
-52
lines changed

tensorcircuit/noisemodel.py

+64-39
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,29 @@
1-
from tensorcircuit.tensorcircuit.abstractcircuit import AbstractCircuit
1+
"""
2+
General Noise Model Construction.
3+
"""
4+
import logging
5+
from tensorcircuit.abstractcircuit import AbstractCircuit
26
from . import Circuit, DMCircuit
37
from .cons import backend
48

9+
logger = logging.getLogger(__name__)
10+
511

612
class NoiseConf:
713
def __init__(self) -> None: # type: ignore
814
self.nc = {} # type: ignore
9-
self.quantum = False
10-
self.readout = False
11-
self.num_quantum = 0
15+
self.has_quantum = False
16+
self.has_readout = False
1217

1318
def add_noise(self, gate_name, kraus): # type: ignore
1419
self.nc[gate_name] = kraus
1520
if gate_name == "readout":
16-
self.readout = True
21+
self.has_readout = True
1722
else:
18-
self.quantum = True
19-
self.num_quantum += 1
23+
self.has_quantum = True
2024

2125

22-
def apply_qir(c, qir, noise_conf, randx=None): # type: ignore
26+
def apply_qir_with_noise(c, qir, noise_conf, status=None): # type: ignore
2327

2428
quantum_index = 0
2529
for d in qir:
@@ -39,74 +43,92 @@ def apply_qir(c, qir, noise_conf, randx=None): # type: ignore
3943

4044
else:
4145
if d["name"] in noise_conf.nc:
42-
quantum_index += 1
4346
if noise_conf.nc[d["name"]].is_unitary is True:
4447
c.unitary_kraus(
4548
noise_conf.nc[d["name"]],
4649
*d["index"],
47-
status=randx[quantum_index - 1]
50+
status=status[quantum_index]
4851
)
4952
else:
5053
c.general_kraus(
5154
noise_conf.nc[d["name"]],
5255
*d["index"],
53-
status=randx[quantum_index - 1]
56+
status=status[quantum_index]
5457
)
58+
quantum_index += 1
5559

5660
return c
5761

5862

59-
def circuit_with_noise(c, noise_conf, randx=None): # type: ignore
63+
def circuit_with_noise(c, noise_conf, status=None): # type: ignore
6064
qir = c.to_qir()
6165
cnew: AbstractCircuit
6266
if isinstance(c, DMCircuit):
6367
cnew = DMCircuit(c._nqubits)
6468
else:
6569
cnew = Circuit(c._nqubits)
66-
cnew = apply_qir(cnew, qir, noise_conf, randx)
70+
cnew = apply_qir_with_noise(cnew, qir, noise_conf, status)
6771
return cnew
6872

6973

70-
def expectation_ps_noisfy(c, x=None, y=None, z=None, noise_conf=NoiseConf(), nmc=1000): # type: ignore
74+
def expectation_ps_noisfy(c, x=None, y=None, z=None, noise_conf=None, nmc=1000, status=None): # type: ignore
7175

72-
if noise_conf.readout is True:
73-
raise ValueError("expectation_ps_noisfy can't support readout error.")
76+
if noise_conf is None:
77+
noise_conf = NoiseConf()
78+
else:
79+
pass
80+
81+
num_quantum = c.gate_count(list(noise_conf.nc.keys()))
7482

83+
if noise_conf.has_readout is True:
84+
logger.warning("expectation_ps_noisfy can't support readout error.")
7585
else:
76-
if noise_conf.quantum is True:
86+
pass
7787

78-
# density matrix
79-
if isinstance(c, DMCircuit):
80-
cnoise = circuit_with_noise(c, noise_conf)
81-
return cnoise.expectation_ps(x=x, y=y, z=z)
88+
if noise_conf.has_quantum is True:
8289

83-
# monte carlo
84-
else:
90+
# density matrix
91+
if isinstance(c, DMCircuit):
92+
cnoise = circuit_with_noise(c, noise_conf)
93+
return cnoise.expectation_ps(x=x, y=y, z=z)
8594

86-
def mcsim(randx): # type: ignore
87-
cnoise = circuit_with_noise(c, noise_conf, randx)
88-
return cnoise.expectation_ps(x=x, y=y, z=z)
95+
# monte carlo
96+
else:
8997

90-
mcsim_vmap = backend.vmap(mcsim, vectorized_argnums=0)
91-
randx = backend.implicit_randu([nmc, noise_conf.num_quantum])
92-
value = backend.mean(mcsim_vmap(randx))
98+
def mcsim(status): # type: ignore
99+
cnoise = circuit_with_noise(c, noise_conf, status)
100+
return cnoise.expectation_ps(x=x, y=y, z=z)
93101

94-
return value
102+
mcsim_vmap = backend.vmap(mcsim, vectorized_argnums=0)
103+
if status is None:
104+
status = backend.implicit_randu([nmc, num_quantum])
105+
else:
106+
pass
107+
value = backend.mean(mcsim_vmap(status))
95108

96-
else:
97-
return c.expectation_ps(x=x, y=y, z=z)
109+
return value
110+
111+
else:
112+
return c.expectation_ps(x=x, y=y, z=z)
98113

99114

100115
def sample_expectation_ps_noisfy( # type: ignore
101-
c, x=None, y=None, z=None, noise_conf=NoiseConf(), nmc=1000, shots=None
116+
c, x=None, y=None, z=None, noise_conf=None, nmc=1000, shots=None, status=None
102117
):
103118

104-
if noise_conf.readout is True:
119+
if noise_conf is None:
120+
noise_conf = NoiseConf()
121+
else:
122+
pass
123+
124+
num_quantum = c.gate_count(list(noise_conf.nc.keys()))
125+
126+
if noise_conf.has_readout is True:
105127
readout_error = noise_conf.nc["readout"]
106128
else:
107129
readout_error = None
108130

109-
if noise_conf.quantum is True:
131+
if noise_conf.has_quantum is True:
110132

111133
# density matrix
112134
if isinstance(c, DMCircuit):
@@ -118,15 +140,18 @@ def sample_expectation_ps_noisfy( # type: ignore
118140
# monte carlo
119141
else:
120142

121-
def mcsim(randx): # type: ignore
122-
cnoise = circuit_with_noise(c, noise_conf, randx)
143+
def mcsim(status): # type: ignore
144+
cnoise = circuit_with_noise(c, noise_conf, status)
123145
return cnoise.sample_expectation_ps(
124146
x=x, y=y, z=z, shots=shots, readout_error=readout_error
125147
)
126148

127149
mcsim_vmap = backend.vmap(mcsim, vectorized_argnums=0)
128-
randx = backend.implicit_randu([nmc, noise_conf.num_quantum])
129-
value = backend.mean(mcsim_vmap(randx))
150+
if status is None:
151+
status = backend.implicit_randu([nmc, num_quantum])
152+
else:
153+
pass
154+
value = backend.mean(mcsim_vmap(status))
130155
return value
131156

132157
else:

tests/test_noisemodel.py

+31-13
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import pytest
22
from pytest_lazyfixture import lazy_fixture as lf
3-
3+
import numpy as np
44

55
import tensorcircuit as tc
66
from tensorcircuit.noisemodel import (
@@ -27,6 +27,8 @@ def test_noisemodel_expectvalue(backend):
2727
readout_error.append([0.4, 0.7]) # readout error of qubit 1
2828

2929
noise_conf1 = NoiseConf()
30+
noise_conf1.add_noise("rx", error1)
31+
noise_conf1.add_noise("h", error3)
3032
noise_conf1.add_noise("readout", readout_error)
3133

3234
c = tc.Circuit(2)
@@ -35,27 +37,37 @@ def test_noisemodel_expectvalue(backend):
3537
c.x(1)
3638
cnoise = circuit_with_noise(c, noise_conf, [0.1] * 2)
3739
value = cnoise.expectation_ps(z=[0, 1])
38-
print("noise_circuit_value", value)
40+
# print("noise_circuit_value", value)
41+
np.testing.assert_allclose(value, -0.18, atol=1e-2)
3942

4043
dmc = tc.DMCircuit(2)
4144
dmc.rx(0, theta=0.4)
4245
dmc.h(0)
4346
dmc.x(1)
4447
cnoise = circuit_with_noise(dmc, noise_conf)
4548
value = cnoise.expectation_ps(z=[0, 1])
46-
print("noise_circuit_value", value)
49+
# print("noise_circuit_value", value)
50+
np.testing.assert_allclose(value, -0.28, atol=1e-2)
4751

4852
value = expectation_ps_noisfy(c, z=[0, 1], nmc=10000)
49-
print("mc", value)
53+
# print("mc", value)
54+
np.testing.assert_allclose(value, 0, atol=1e-2)
5055

5156
value = expectation_ps_noisfy(dmc, z=[0, 1])
52-
print("dm", value)
57+
# print("dm", value)
58+
np.testing.assert_allclose(value, 0, atol=1e-2)
5359

5460
value = expectation_ps_noisfy(c, z=[0, 1], noise_conf=noise_conf, nmc=10000)
55-
print("mc_quantum", value)
61+
# print("mc_quantum", value)
62+
np.testing.assert_allclose(value, -0.28, atol=1e-2)
5663

5764
value = expectation_ps_noisfy(dmc, z=[0, 1], noise_conf=noise_conf)
58-
print("dm_quantum", value)
65+
# print("dm_quantum", value)
66+
np.testing.assert_allclose(value, -0.28, atol=1e-2)
67+
68+
value = expectation_ps_noisfy(c, z=[0, 1], noise_conf=noise_conf1, nmc=10000)
69+
# print("mc_readout", value)
70+
np.testing.assert_allclose(value, -0.28, atol=1e-2)
5971

6072

6173
@pytest.mark.parametrize("backend", [lf("npb"), lf("tfb"), lf("jaxb")])
@@ -87,24 +99,30 @@ def test_noisemodel_sample(backend):
8799
value = sample_expectation_ps_noisfy(
88100
c, z=[0, 1], noise_conf=noise_conf1, nmc=100000
89101
)
90-
print("noise_nmc_read", value)
102+
# print("noise_nmc_read", value)
103+
np.testing.assert_allclose(value, -0.06, atol=1e-2)
91104

92105
value = sample_expectation_ps_noisfy(c, z=[0, 1], noise_conf=noise_conf, nmc=10000)
93-
print("noise_nmc_read_quantum", value)
106+
# print("noise_nmc_read_quantum", value)
107+
np.testing.assert_allclose(value, -0.133, atol=1e-2)
94108

95109
value = sample_expectation_ps_noisfy(c, z=[0, 1], noise_conf=noise_conf2, nmc=10000)
96-
print("noise_nmc_quantum", value)
110+
# print("noise_nmc_quantum", value)
111+
np.testing.assert_allclose(value, -0.28, atol=1e-2)
97112

98113
dmc = tc.DMCircuit(2)
99114
dmc.rx(0, theta=0.4)
100115
dmc.h(0)
101116
dmc.x(1)
102117

103118
value = sample_expectation_ps_noisfy(dmc, z=[0, 1], noise_conf=noise_conf1)
104-
print("noise_dm_read", value)
119+
# print("noise_dm_read", value)
120+
np.testing.assert_allclose(value, -0.06, atol=1e-2)
105121

106122
value = sample_expectation_ps_noisfy(dmc, z=[0, 1], noise_conf=noise_conf)
107-
print("noise_dm_read_quantum", value)
123+
# print("noise_dm_read_quantum", value)
124+
np.testing.assert_allclose(value, -0.133, atol=1e-2)
108125

109126
value = sample_expectation_ps_noisfy(dmc, z=[0, 1], noise_conf=noise_conf2)
110-
print("noise_nmc_quantum", value)
127+
# print("noise_nmc_quantum", value)
128+
np.testing.assert_allclose(value, -0.28, atol=1e-2)

0 commit comments

Comments
 (0)