噪声模拟器
MindQuantum 中包含各种噪声信道,利用噪声信道我们可以对真实的量子芯片进行模拟。在 MindQuantum 中,我们定义了各种 ChannelAdder,可以有选择性的在量子线路的不同位置添加噪声信道,依次完成含噪声的量子模拟。下面介绍如何利用 MindQuantum 完成此任务。
ChannelAdder
ChannelAdder 是一个能够在量子线路特定位置添加特定信道的处理器,例如在测量门后添加比特翻转信道。ChannelAdder 类主要由三个函数构成,_accepter()、_excluder() 和 _handler(BasicGate),其功能对应如下:
- _accepter():返回一个由函数构成的列表,称为接受规则集,其中每个接受规则函数的输入都是一个量子门,当函数返回值为- True时表示我们可以在该量子门后添加信道。
- _excluder():返回一个由函数构成的列表,称为拒绝规则集,其中每个拒绝规则函数的输入都是一个量子门,当函数返回值为- True时表示我们拒绝在该量子门后添加信道。
- _handler(BasicGate):输入一个量子门,返回一段量子线路,表示在输入量子门后添加一段自定义的信道。
我们重定义类 ChannelAdder 的 __call__ 函数,直接调用 ChannelAdder 即可生成处理后的量子线路。 下面介绍几种 ChannelAdder。
BitFlipAdder
BitFlipAdder 的接口定义为:
BitFlipAdder(flip_rate: float, with_ctrl=True, focus_on: int = None, add_after: bool = True)
该 Adder 会在量子门后添加一个比特翻转信道,接口的参数含义为:
- flip_rate (float):比特翻转信道的翻转概率。 
- with_ctrl (bool):是否在控制位上添加比特。默认值: - True。
- focus_on (bool):只将该噪声信道作用在 - focus_on比特上。如果为- None,则作用在量子门的所有比特上。默认值:- None。
- add_after (bool):是否在量子门后面添加信道。如果为 - False,信道将会加在量子门前面。默认值:- True。
例如,我们可以通过如下接口,在给定量子线路的每个量子门后都添加一个翻转概率为 0.3 的比特翻转信道:
[1]:
from mindquantum.core.circuit.channel_adder import BitFlipAdder
from mindquantum.core import gates as G
from mindquantum.core.circuit import Circuit
circ = Circuit()+G.H(0)+G.RX('a').on(1)+G.Z(1, 0)
circ.svg()
[1]:
[2]:
bit_flip_adder = BitFlipAdder(0.3, with_ctrl=False)
new_circ = bit_flip_adder(circ)
new_circ.svg()
[2]:
MeasureAccepter
MeasureAccepter()
该 Adder 会选择对应的测量门,它目前只是一个 Accepter,不会改变量子线路中的任何门,需要利用 MixerAdder,跟其他的 Adder 搭配使用。
MixerAdder
MixerAdder(adders: typing.List[ChannelAdderBase])
MixerAdder 可以将多个 Adder 混合起来,保证量子门在每一个 Adder 中的接受函数集和拒绝函数集同时满足时,顺序添加 _handler 产生的量子线路。
举例来说,我们可以将上文提到的 BitFlipAdder 和 MeasureAccepter 混合起来,达到只在测量门前添加比特翻转信道的功能:
[3]:
from IPython.display import display_svg
from mindquantum.core.circuit.channel_adder import MixerAdder, MeasureAccepter
mixer = MixerAdder([
    BitFlipAdder(flip_rate=0.01),
    MeasureAccepter(),
], add_after=False)
print(mixer)
circ = Circuit() + G.H(0) + G.RX('a').on(1) + G.Z(1, 0) + G.Measure().on(0)
display_svg(circ.svg())
new_circ = mixer(circ)
new_circ.svg()
MixerAdder<
  BitFlipAdder<flip_rate=0.01, with_ctrl=True>
  MeasureAccepter<>
>
[3]:
SequentialAdder
SequentialAdder(adders: typing.List[ChannelAdderBase])
SequentialAdder 是由多个 Adder 顺序构成类,量子线路会经过 SequentialAdder 中的 Adder 依次处理,生成最终的量子线路。例如,我们想构建一个先在测量门前添加一个 \(p=0.01\) 的比特翻转信道,然后在 q1 比特上的非测量门和非噪声信道后添加 \(p=0.05\)
的去极化信道。
自定义 Adder
我们首先自定义在某个比特添加比特翻转信道的 Adder。
[4]:
from mindquantum.core.circuit.channel_adder import ChannelAdderBase, SequentialAdder
class CustomDepolarizingAdder(ChannelAdderBase):
    def __init__(self, q, p):
        self.q = q
        self.p = p
        super().__init__()
    def _accepter(self):
        return [lambda x: self.q in x.obj_qubits or self.q in x.ctrl_qubits]
    def _excluder(self):
        return  [lambda x: isinstance(x, (G.Measure, G.NoiseGate))]
    def _handler(self, g):
        return Circuit([G.DepolarizingChannel(self.p).on(self.q)])
    def __repr__(self):
        return f"CustomDepolarizingAdder<q={self.q}, flip_rate={self.p}>"
seq_adder = SequentialAdder([
    MixerAdder([
        MeasureAccepter(),
        BitFlipAdder(flip_rate=0.01),
    ], add_after=False),
    CustomDepolarizingAdder(q=1, p=0.05),
])
print(seq_adder)
SequentialAdder<
  MixerAdder<
    MeasureAccepter<>
    BitFlipAdder<flip_rate=0.01, with_ctrl=True>
  >
  CustomDepolarizingAdder<q=1, flip_rate=0.05>
>
[5]:
circ = Circuit() + G.H(0) + G.RX('a').on(1) + G.Z(1, 0) + G.Measure().on(0)
display_svg(circ.svg())
new_circ = seq_adder(circ)
new_circ.svg()
[5]:
上述自定义量子信道也可以通过 MindQuantum 中的预定义信道搭建而成。
[6]:
from mindquantum.core.circuit import ReverseAdder, NoiseExcluder, NoiseChannelAdder
seq_adder = SequentialAdder([
    MixerAdder([
        MeasureAccepter(),
        BitFlipAdder(flip_rate=0.01),
    ], add_after=False),
    MixerAdder([
        ReverseAdder(MeasureAccepter()),
        NoiseExcluder(),
        NoiseChannelAdder(G.DepolarizingChannel(0.05), focus_on=1),
    ])
])
print(seq_adder)
SequentialAdder<
  MixerAdder<
    MeasureAccepter<>
    BitFlipAdder<flip_rate=0.01, with_ctrl=True>
  >
  MixerAdder<
    ReverseAdder<
      MeasureAccepter<>
    >
    NoiseExcluder<>
    NoiseChannelAdder<channel=DC(p=1/20), with_ctrl=True>
  >
>
[7]:
seq_adder(circ).svg()
[7]:
更复杂的例子
下面我们来搭建一个更复杂的 ChannelAdder 例子,在该例子中,芯片的不同比特上的单比特门操作的噪声可以忽略不记,而双比特门在不同比特上具有不同的去极化信道,且线路的测量具有一个翻转概率为0.01的比特翻转错误。
我们假设不同比特上的去极化信道为:
[8]:
dc0 = G.DepolarizingChannel(0.01)
dc1 = G.DepolarizingChannel(0.02)
dc2 = G.DepolarizingChannel(0.03)
然后,我们定义出满足要求的 Adder:
[9]:
from mindquantum.core.circuit import QubitNumberConstrain
noise_adder = SequentialAdder([
    MixerAdder([
        NoiseExcluder(),
        ReverseAdder(MeasureAccepter()),
        QubitNumberConstrain(2),
        NoiseChannelAdder(dc0, focus_on=0),
    ]),
    MixerAdder([
        NoiseExcluder(),
        ReverseAdder(MeasureAccepter()),
        QubitNumberConstrain(2),
        NoiseChannelAdder(dc1, focus_on=1),
    ]),
    MixerAdder([
        NoiseExcluder(),
        ReverseAdder(MeasureAccepter()),
        QubitNumberConstrain(2),
        NoiseChannelAdder(dc2, focus_on=2),
    ]),
    MixerAdder([
        NoiseExcluder(),
        MeasureAccepter(),
        BitFlipAdder(0.01)
    ], add_after=False),
])
noise_adder
[9]:
SequentialAdder<
  MixerAdder<
    NoiseExcluder<>
    ReverseAdder<
      MeasureAccepter<>
    >
    QubitNumberConstrain<n_qubits=2, with_ctrl=True>
    NoiseChannelAdder<channel=DC(p=1/100), with_ctrl=True>
  >
  MixerAdder<
    NoiseExcluder<>
    ReverseAdder<
      MeasureAccepter<>
    >
    QubitNumberConstrain<n_qubits=2, with_ctrl=True>
    NoiseChannelAdder<channel=DC(p=1/50), with_ctrl=True>
  >
  MixerAdder<
    NoiseExcluder<>
    ReverseAdder<
      MeasureAccepter<>
    >
    QubitNumberConstrain<n_qubits=2, with_ctrl=True>
    NoiseChannelAdder<channel=DC(p=0.03), with_ctrl=True>
  >
  MixerAdder<
    NoiseExcluder<>
    MeasureAccepter<>
    BitFlipAdder<flip_rate=0.01, with_ctrl=True>
  >
>
假设我们想要处理的量子线路是哈密顿量 \(H=a_{01} Z_0Z_1 + a_{12} Z_1Z_2 + b_0 X_0 + b_1 X_1 + b_2 X_2\) 含时演化的一阶Trotter近似线路:
[10]:
from mindquantum.core.operators import TimeEvolution, QubitOperator
ham = sum([
    QubitOperator('X0', 'b_0'),
    QubitOperator('X1', 'b_1'),
    QubitOperator('X2', 'b_2'),
    QubitOperator('Z0 Z1', 'a_01'),
    QubitOperator('Z1 Z2', 'a_12')
])
ham
[10]:
 b_0 [X0] +
 b_1 [X1] +
 b_2 [X2] +
a_01 [Z0 Z1] +
a_12 [Z1 Z2]
[11]:
circ = TimeEvolution(ham).circuit
circ.barrier()
circ.measure_all()
circ.svg()
[11]:
此线路经过上述定义的 noise_adder 处理后的量子线路为:
[12]:
noise_adder(circ).svg()
[12]:
ChannelAdder 列表
下面列举出 MindQuantum 中现有的一些 ChannelAdder,并给出具体含义:
| 功能 | |
|---|---|
| 在量子门前面或者后面添加信道 | |
| 添加一个单比特量子信道 | |
| 选取测量门 | |
| 翻转给定信道添加器的接受和拒绝规则 | |
| 排除噪声门 | |
| 在量子门前面或者后面添加一个比特翻转信道 | |
| 在子添加器的接受集被满足、拒绝集被拒绝时依次执行所有的添加器 | |
| 依次执行每一个添加器 | |
| 只将噪声信道作用在比特数为  | |
| 只将噪声信道作用在给定比特序号的量子门上 | |
| 选择想要的量子门添加信道 | |
| 添加去极化信道 | 
MindQuantum 中 ChannelAdder 的API接口文档请参考:channel_adder
基于 ChannelAdder 的噪声模拟器
我们可以将如上定义的各种 Adder 与现有的模拟器组合,构成一个含噪声模拟器。
[13]:
from mindquantum.simulator import Simulator
from mindquantum.simulator.noise import NoiseBackend
noiseless_sim = Simulator('mqvector', 2)
noiseless_circ = Circuit().h(0).rx(1.0, 1).z(1, 0).measure(1)
display_svg(noiseless_circ.svg())
res1 = noiseless_sim.sampling(noiseless_circ, shots=10000)
display(res1.svg())
[14]:
noise_sim = Simulator(NoiseBackend('mqvector', 2, seq_adder))
res2 = noise_sim.sampling(noiseless_circ, shots=10000)
display(res2.svg())
display(noise_sim.backend.transform_circ(noiseless_circ).svg())
[15]:
from mindquantum.utils.show_info import InfoTable
InfoTable('mindquantum', 'scipy', 'numpy')
[15]:
| Software | Version | 
|---|---|
| mindquantum | 0.9.11 | 
| scipy | 1.10.1 | 
| numpy | 1.24.4 | 
| System | Info | 
| Python | 3.8.17 | 
| OS | Linux x86_64 | 
| Memory | 16.62 GB | 
| CPU Max Thread | 16 | 
| Date | Tue Jan 2 15:11:15 2024 |