import deepquantum as dq
import numpy as np
import torch

print('version', dq.__version__)
version 4.2.0

基于测量的量子计算(MBQC)教程#

构建Pattern#

通过转译QubitCircuit线路构建Pattern#

构建QubitCircuit

cir = dq.QubitCircuit(2)
cir.h(0)
cir.h(1)
cir.cnot(0, 1)
cir.draw()
../_images/b2e65d31f377a3fd2085630ce4d642b95132d4b6463e310036bb12525aeab706.png

转译为MBQC的Pattern

# Transpile circuit to measurement pattern
pattern = cir.pattern()
print(pattern)
Pattern(
  (init_state): GraphState(
    (subgraphs): ModuleList(
      (0): SubGraphState(nodes_state=[0], nodes=[0])
      (1): SubGraphState(nodes_state=[1], nodes=[1])
    )
  )
  (commands): Sequential(
    (0): Node(nodes=[2])
    (1): Entanglement(nodes=[0, 2])
    (2): Measurement(nodes=[0], plane=XY, angle=0.0, s_domain=set(), t_domain=set())
    (3): Correction(basis=x, nodes=[2], domain={0})
    (4): Node(nodes=[3])
    (5): Entanglement(nodes=[1, 3])
    (6): Measurement(nodes=[1], plane=XY, angle=0.0, s_domain=set(), t_domain=set())
    (7): Correction(basis=x, nodes=[3], domain={1})
    (8): Node(nodes=[4, 5])
    (9): Entanglement(nodes=[3, 4])
    (10): Entanglement(nodes=[2, 4])
    (11): Entanglement(nodes=[4, 5])
    (12): Measurement(nodes=[3], plane=XY, angle=0.0, s_domain=set(), t_domain=set())
    (13): Measurement(nodes=[4], plane=XY, angle=0.0, s_domain=set(), t_domain=set())
    (14): Correction(basis=x, nodes=[5], domain={4})
    (15): Correction(basis=z, nodes=[5], domain={3})
    (16): Correction(basis=z, nodes=[2], domain={3})
  )
)

如果QubitCircuit初态是batch形式,转译后的Pattern初态依然是batch形式。

n_qubits = 2
batch_size = 5
init_state = torch.rand(batch_size, 2**n_qubits)  # 输入QubitCiurcuit后会自动归一化

cir = dq.QubitCircuit(n_qubits, init_state=init_state)
cir.h(0)
cir.h(1)
cir.cnot(0, 1)

pattern = cir.pattern()
print(pattern.init_state.full_state.shape)
print(pattern.init_state.full_state)
torch.Size([5, 4, 1])
tensor([[[0.7524+0.j],
         [0.1355+0.j],
         [0.6322+0.j],
         [0.1257+0.j]],

        [[0.5817+0.j],
         [0.4449+0.j],
         [0.6000+0.j],
         [0.3220+0.j]],

        [[0.0243+0.j],
         [0.3302+0.j],
         [0.0513+0.j],
         [0.9422+0.j]],

        [[0.2712+0.j],
         [0.5765+0.j],
         [0.3570+0.j],
         [0.6831+0.j]],

        [[0.4778+0.j],
         [0.4311+0.j],
         [0.5746+0.j],
         [0.5057+0.j]]])

可视化构建的图态。其中,方形node表示输入,edge表示node间存在CZ纠缠,蓝色node表示待测,剩余的灰色node表示输出。

绿色/红色虚线表示测量角度对于t domain/s domain的依赖。因为转译完得到的是未经优化的wild pattern,中间的Z/X修正尚未转移到测量角度上,所以图中并没有显示。

pattern.draw()
../_images/1b5e6dea453e4501bf7963d03d92a747eca678fb56c52befbc3ba89b58eb1a32.png

手动构建Pattern#

除了通过QubitCircuit的转译,用户可以初始化Pattern后,通过手动添加NEMCcommands,构建自定义的Pattern

输入的节点可以用初始化参数中nodes_state设置,类型可以是int,代表初始化节点的数量,也可以用List指定节点的编号。

而初态用参数state设置,默认为全 \( \left |+\right \rangle\) 态。除了输入自定义的态矢,可以用str类型的输入,支持'plus''minus''zero''one'

pattern = dq.Pattern(nodes_state=[0, 1])
## 等效为 pattern = dq.Pattern(nodes_state=2)

print(pattern.init_state.full_state)

pattern.draw()
tensor([[0.5000+0.j],
        [0.5000+0.j],
        [0.5000+0.j],
        [0.5000+0.j]])
../_images/725746dcef9c8a486866841aceca9519755f59d91130a11545c4d8a6cec413e9.png
# 自定义初态
pattern = dq.Pattern(nodes_state=[0, 1], state=[1, 0, 0, 0])
print(pattern.init_state.full_state)

# 初态str表示
pattern = dq.Pattern(nodes_state=[0, 1], state='minus')
print(pattern.init_state.full_state)

pattern = dq.Pattern(nodes_state=[0, 1], state='zero')
print(pattern.init_state.full_state)

pattern = dq.Pattern(nodes_state=[0, 1], state='one')
print(pattern.init_state.full_state)
tensor([[1.+0.j],
        [0.+0.j],
        [0.+0.j],
        [0.+0.j]])
tensor([[ 0.5000+0.j],
        [-0.5000+0.j],
        [-0.5000+0.j],
        [ 0.5000-0.j]])
tensor([[1.+0.j],
        [0.+0.j],
        [0.+0.j],
        [0.+0.j]])
tensor([[0.+0.j],
        [0.+0.j],
        [0.+0.j],
        [1.+0.j]])

可以在nodes_state的基础上,额外加入edgesnodes作为输入的初始图态。

pattern = dq.Pattern(nodes_state=[0, 1], nodes=[2, 3], edges=[[2, 3]])

pattern.draw()
../_images/46a1f260cb5883384af6bb6a75017b4d19d22c8bcec59cbefcb8ff2103ba604c.png

根据NEMC Commands序列,生成特定的Pattern

Command

定义

Pattern函数

\(N_i\)

Node (qubit) preparation command with node index \(i\)

\(n(i)\)

\(E_{ij}\)

Entanglement command which apply \(CZ\) gate to nodes \((i, j)\)

\(e(i, j)\)

\(^t[M_i^{\lambda, \alpha}]^s\)

Measurement command which perform measurement of node \(i\) ,with
measurement plane \(\lambda = XY, YZ\) or \(XZ\),
measurement angle \(\alpha\) defined on the plane \(\lambda\),
\(s\) and \(t\) feedforward domains that adaptively changes the measurement angles to \(\alpha' = (-1)^{q_s}\alpha + \pi q_t\),
where \(q_s, q_t\) are the sum of all measurement outcomes in the \(s\) and \(t\) domains.

\(m(i, \alpha, \lambda, t, s)\)

\(X_i^s\)

Correction X command applied to qubit \(i\) with signal domain \(s\)

\(x(i, s)\)

\(Z_i^s\)

Correction Z command applied to qubit \(i\) with signal domain \(s\)

\(z(i, s)\)

例如,生成 \( X_3^{s_0+s_1}\ ^{t_1} [M_2^{\pi}]^{s_0}E_{23}N_3[M_1^{\pi}]^{s_0} M_0^{\pi}E_{12}E_{02}N_2E_{01}N_1N_0\)

pattern = dq.Pattern(nodes_state=[0, 1])
pattern.n(2)
pattern.e(0, 2)
pattern.e(1, 2)
pattern.m(node=0, angle=np.pi)
pattern.m(node=1, angle=np.pi, s_domain=[0])
pattern.n(3)
pattern.e(2, 3)
pattern.m(node=2, angle=np.pi, s_domain=[0], t_domain=[1])
pattern.x(node=3, domain=[0, 1])
pattern.draw()
../_images/9b2b39d8ca9e87678dccef4aebdf7d7bb8fdcc32963e547e817eb47cc9c976cc.png

优化Pattern#

进行standardize操作,将Pattern从右向左按NEMC的指令类型进行排列,形成标准形式。

注意,相比wild pattern,standard form会占用更多内存。如果标准化后出现内存溢出的报错,可以尝试对wild pattern直接进行前向演化。

pattern.standardize()
print(pattern)
Pattern(
  (init_state): GraphState(
    (subgraphs): ModuleList(
      (0): SubGraphState(nodes_state=[0, 1], nodes=[0, 1])
    )
  )
  (commands): Sequential(
    (0): Node(nodes=[2])
    (1): Node(nodes=[3])
    (2): Entanglement(nodes=[0, 2])
    (3): Entanglement(nodes=[1, 2])
    (4): Entanglement(nodes=[2, 3])
    (5): Measurement(nodes=[0], plane=XY, angle=3.1415927410125732, s_domain=set(), t_domain=set())
    (6): Measurement(nodes=[1], plane=XY, angle=3.1415927410125732, s_domain={0}, t_domain=set())
    (7): Measurement(nodes=[2], plane=XY, angle=3.1415927410125732, s_domain={0}, t_domain={1})
    (8): Correction(basis=x, nodes=[3], domain={0, 1})
  )
)

通过signal shifting 进一步优化,目的是消除测量角度对于t_domain的依赖(Z-dependency),从而降低量子深度。

pattern.shift_signals()
print(pattern)
Pattern(
  (init_state): GraphState(
    (subgraphs): ModuleList(
      (0): SubGraphState(nodes_state=[0, 1], nodes=[0, 1])
    )
  )
  (commands): Sequential(
    (0): Node(nodes=[2])
    (1): Node(nodes=[3])
    (2): Entanglement(nodes=[0, 2])
    (3): Entanglement(nodes=[1, 2])
    (4): Entanglement(nodes=[2, 3])
    (5): Measurement(nodes=[0], plane=XY, angle=3.1415927410125732, s_domain=set(), t_domain=set())
    (6): Measurement(nodes=[1], plane=XY, angle=3.1415927410125732, s_domain={0}, t_domain=set())
    (7): Measurement(nodes=[2], plane=XY, angle=3.1415927410125732, s_domain={0}, t_domain=set())
    (8): Correction(basis=x, nodes=[3], domain={0, 1})
  )
)

通过图态的可视化,可以观察到signal shifting后的测量不再依赖于绿色的Z修正。

pattern.draw()
../_images/b0a37b6f43b55a829c78032754e4c3e5d0fc5542a8b5149d85eb2f4d39c11798.png

执行MBQC模拟#

前向演化#

和DeepQuantum其它模块一样,仅需一个前向函数即可执行对Pattern的模拟。

pattern()
GraphState(
  (subgraphs): ModuleList(
    (0): SubGraphState(nodes_state=[3], nodes=[3])
  )
)

返回的结果是末态输出的GraphState,使用属性full_state可以得到末态的态矢。

state = pattern().full_state
print(state)
tensor([[-0.7071+6.1817e-08j],
        [-0.7071+6.1817e-08j]])

对应的测量结果由GraphStatemeasure_dict保存:

print(pattern.state.measure_dict)
defaultdict(list, {0: [1], 1: [1], 2: [1]})

支持通过 data 输入Patternencode=True 的command参数(即测量角度),通过 state 指定初态,对Pattern进行演化:

pattern = dq.Pattern(nodes_state=[0, 1])
pattern.n(2)
pattern.e(0, 2)
pattern.e(1, 2)
pattern.m(node=0, encode=True)
pattern.m(node=1, encode=True, s_domain=[0])
pattern.x(node=2, domain=[0, 1])

angle = torch.randn(2)
print(pattern(data=angle).full_state)
tensor([[0.8211+0.5634j],
        [0.0754+0.0517j]])

初态的类型需要是GraphState

init_graph_state = dq.GraphState([0, 1], state=[1, 0, 0, 0])

print(pattern(data=angle, state=init_graph_state).full_state)
tensor([[0.7071+0.j],
        [0.7071+0.j]])

支持batch输入#

测量角度的batch输入:

angle = torch.randn(6, 2)
print(pattern(data=angle).full_state)
tensor([[[ 0.0848-0.9064j],
         [ 0.0386-0.4119j]],

        [[ 0.0642+0.6187j],
         [-0.0809-0.7788j]],

        [[-0.1213-0.0096j],
         [-0.9895-0.0783j]],

        [[-0.0070-0.0196j],
         [-0.3388-0.9406j]],

        [[-0.0062-0.0012j],
         [-0.9820-0.1889j]],

        [[-0.3533+0.0935j],
         [-0.8998+0.2382j]]])

初态的batch输入:

init_graph_state = dq.GraphState([0, 1], state=[[1, 0, 0, 0], [0, 1, 0, 0]])

print(pattern(state=init_graph_state).full_state)
tensor([[[-3.0909e-08-0.7071j],
         [-3.0909e-08-0.7071j]],

        [[ 1.2410e-01-0.6961j],
         [-1.2410e-01+0.6961j]]])

也支持转译前QubitCircuit中参数化门的encode:

cir = dq.QubitCircuit(2)
cir.h(0)
cir.rz(0, encode=True)
cir.ry(1, encode=True)
cir.cnot(0, 1)

pattern = cir.pattern()

data = torch.randn(2)
print(pattern(data=data).full_state)

data = torch.randn(6, 2)
print(pattern(data=data).full_state)
tensor([[-0.6325+0.2172j],
        [ 0.2172-0.0746j],
        [ 0.2232-0.0543j],
        [-0.6498+0.1580j]])
tensor([[[-0.1562+0.6707j],
         [-0.0364+0.1562j],
         [-0.1566-0.0348j],
         [-0.6723-0.1493j]],

        [[-0.2429-0.6104j],
         [ 0.0967+0.2429j],
         [-0.1348+0.2241j],
         [ 0.3386-0.5630j]],

        [[ 0.2640+0.5887j],
         [-0.1184-0.2640j],
         [-0.2793-0.0755j],
         [ 0.6229+0.1683j]],

        [[-0.2568-0.5965j],
         [ 0.1106+0.2568j],
         [ 0.2546+0.1156j],
         [-0.5914-0.2685j]],

        [[-0.5688+0.2805j],
         [ 0.2805-0.1383j],
         [-0.2847+0.1294j],
         [ 0.5773-0.2624j]],

        [[-0.1979-0.6466j],
         [ 0.0605+0.1979j],
         [-0.0180+0.2061j],
         [ 0.0589-0.6736j]]])

支持自动微分#

MBQC模块支持基于PyTorch的自动微分,用户可以利用这一特性设计和模拟含梯度优化的变分算法(VMBQC)。

data = torch.randn(2, requires_grad=True)
print(pattern(data=data).full_state)
tensor([[-0.1982-0.6463j],
        [ 0.0608+0.1982j],
        [ 0.0490-0.2015j],
        [-0.1599+0.6568j]], grad_fn=<SqueezeBackward1>)