量子线路高阶操作
在前面变分量子线路操作指导中介绍了量子线路的基本用法。接下来,我们将进一步探索MindSpore Quantum为量子线路定义的一些高阶操作的用法。
mindquantum.core.circuit.controlled
controlled 方法用于对任意量子线路或量子算符添加控制量子比特(可以是多个)。
例如,我们构建一个仅包含两个量子比特的量子线路,并通过 controlled 方法对其添加一个控制量子比特——\(q_2\):
[1]:
from mindquantum.algorithm.library import qft
from mindquantum.core.circuit import controlled
u1 = qft(range(2)) # 构建量子线路
u1.svg()
[1]:
[2]:
u2 = controlled(u1)(2) # 对线路添加控制量子位q2,返回一个新的线路
u2.svg()
[2]:
实际上,controlled() 返回的是一个函数。例如:
[3]:
u3 = controlled(u1)
我们可通过调用u3来对初始线路u1添加控制量子位,和上面的效果是一样的:
[4]:
u4 = u3(2)
u4.svg()
[4]:
注意:添加的控制量子比特不能是线路中已存在的某个门的目标量子比特,否则会报错!
另外,我们还可以对量子线路批量添加控制位。例如,在下面的示例中,我们对\(q_0\)和\(q_1\)分别添加控制位——\(q_2\)和\(q_3\):
[5]:
u = controlled(qft)
u = u([2, 3], [0, 1]) # 批量添加控制位
u.svg()
[5]:
mindquantum.core.circuit.dagger
dagger 方法用于求量子线路或量子算符的厄米共轭。
以下示例提供了两种进行 dagger 操作的方式:
[6]:
from mindquantum.core.circuit import dagger
u1 = qft(range(3))
u1.svg()
[6]:
[7]:
u2 = dagger(u1)
u2.svg()
[7]:
[8]:
u3 = dagger(qft)
u4 = u3(range(3))
u4.svg()
[8]:
可看到,两种方式得到的线路是相同的。
mindquantum.core.circuit.apply
apply 方法用于将量子线路或量子算符作用在指定的量子比特(可以是多个)上。
[9]:
from mindquantum.core.circuit import apply
u1 = qft([0, 1])
circuit1 = apply(u1, [1, 0]) # 将量子线路u1作用在比特q1, q0上
circuit1.svg()
[9]:
[10]:
u2 = apply(qft, [1, 0]) # 将qft作用在比特q0, q1上
circuit2 = u2([0, 1])
circuit2.svg()
[10]:
mindquantum.core.circuit.add_prefix
add_prefix 方法用于在参数化量子电路或参数化量子算符的参数名上加上前缀。这在神经网络分层中十分有用,例如:
[11]:
from mindquantum.core.circuit import add_prefix, Circuit
from mindquantum.core.gates import RX, H
circ = Circuit().rx("theta", 0)
circ.svg()
[11]:
[12]:
circ = add_prefix(circ, 'l0') # 添加后,参数"theta"就变成了"l0_theta"
circ.svg()
[12]:
我们可以在含参量子门作用于具体的量子比特后对其参数名称添加前缀,也可以在其还未应用于量子比特的时候添加。例如:
[13]:
u = lambda qubit: Circuit([H.on(0), RX('a').on(qubit)])
u1 = u(0)
u1 = add_prefix(u1, 'ansatz')
u1.svg()
[13]:
[14]:
u2 = add_prefix(u, 'ansatz')
u2 = u2(0)
u2.svg()
[14]:
mindquantum.core.circuit.change_param_name
change_param_name 方法用于修改参数化量子电路或参数化量子算符的参数名。
[15]:
from mindquantum.core.circuit import change_param_name, Circuit
from mindquantum.core.gates import RX, H
u = lambda qubit: Circuit([H.on(0), RX('a').on(qubit)])
u1 = u(0)
u1 = change_param_name(u1, {'a': 'b'})
u1.svg()
[15]:
[16]:
u2 = change_param_name(u, {'a': 'b'})
u2 = u2(0)
u2.svg()
[16]:
mindquantum.core.circuit.UN
UN 模块用于将量子门作用于不同的目标量子比特和控制量子比特。
一般格式如下:mindquantum.circuit.UN(gate, maps_obj, maps_ctrl=None)
,参数gate
是要执行的量子门,maps_obj
是需要执行该量子门的目标量子比特,maps_ctrl
是控制量子比特(无控制量子位时为None
)。若每个量子比特位都执行同一不含参的量子门,则可以直接使用UN(gate, N)
,N
表示量子比特个数。
以下是一个简单的示例,我们在构建的线路中对每一位量子比特都应用一个 H 门:
[17]:
from mindquantum.core.circuit import change_param_name, Circuit, UN
from mindquantum.core.gates import X, H, SWAP
circuit1 = Circuit()
circuit1 += UN(H, 4) # 将H门作用在每一位量子比特上
circuit1.svg()
[17]:
以下示例中,我们对量子比特\(q_2\)和\(q_0\)、\(q_3\)和\(q_1\)分别添加一个CNOT门,其中\(q_2\)为控制位,\(q_0\)为目标位;\(q_3\)为控制位,\(q_1\)为目标位:
[18]:
circuit2 = UN(X, maps_obj=[0, 1], maps_ctrl=[2, 3])
circuit2.svg()
[18]:
针对类似 SWAP 门的用法如下:
[19]:
circuit3 = UN(SWAP, maps_obj=[[0, 1], [2, 3]]).x(2, 1)
circuit3.svg()
[19]:
mindquantum.core.circuit.shift
shift 方法用于修改给定线路的量子位范围,参数为要挪动的步长。注意,步长不能为负数。并且,只能挪到最后一个量子比特,不能循环到\(q_0\)(第一个量子位)。
[20]:
from mindquantum.core.circuit import shift, Circuit
from mindquantum.core.gates import X
circ = Circuit().x(1, 0)
circ.svg()
[20]:
[21]:
circ = shift(circ, 1)
circ.svg() # 线路作用的量子比特从q0,q1变为q1,q2
[21]:
案例——鸢尾花分类:搭建Encoder
以上高阶操作的示例显示了量子线路高阶操作的适用性及便捷性,如果我们进一步将它们组合起来用于构建量子线路,又会产生什么神奇魔力呢?
接下来我们将以 通过量子神经网络对鸢尾花进行分类 的案例中 搭建Encoder 部分为例,搭建下图所示的量子线路:
[22]:
from mindquantum.core.circuit import shift, add_prefix, Circuit, UN
from mindquantum.core.gates import RZ, X, H
template = Circuit([X.on(1, 0), RZ('alpha').on(1), X.on(1, 0)])
encoder = UN(H, 4) + (RZ(f'{i}_alpha').on(i) for i in range(4)) + sum(add_prefix(shift(template, i), f'{i+4}') for i in range(3))
encoder.summary()
Circuit Summary ╭──────────────────────┬───────────────────────────────────────────────────────────────╮ │ Info │ value │ ├──────────────────────┼───────────────────────────────────────────────────────────────┤ │ Number of qubit │ 4 │ ├──────────────────────┼───────────────────────────────────────────────────────────────┤ │ Total number of gate │ 17 │ │ Barrier │ 0 │ │ Noise Channel │ 0 │ │ Measurement │ 0 │ ├──────────────────────┼───────────────────────────────────────────────────────────────┤ │ Parameter gate │ 7 │ │ 7 ansatz parameters │ 0_alpha, 1_alpha, 2_alpha, 3_alpha, 4_alpha, 5_alpha, 6_alpha │ ╰──────────────────────┴───────────────────────────────────────────────────────────────╯
[23]:
encoder.svg()
[23]:
在上面的代码中,我们使用UN模块将不含参数的H门作用于目标量子比特\(q_0\)~\(q_3\),然后将RZ(i_alpha)门作用于第i位量子比特。 接着,观察到线路中有三个一样的模块,它们都由一个受控X门、一个RZ门和一个受控X门构成,因此,我们构造对应的模板template,它由一个受\(q_0\)控制、作用在\(q_1\)的X门,一个作用在\(q_1\)的RZ门和一个受\(q_0\)控制、作用在\(q_1\)的X门构成。然后我们通过shift(template, i)来改变模板作用的量子比特范围,构建三个结构相同但作用的量子比特范围相差1的模块,其涉及的量子比特范围分别为\(q_0\)和\(q_1\)、\(q_1\)和\(q_2\)、\(q_2\)和\(q_3\)。 最后,我们使用add_prefix方法为通过shift构造的所有含参量子门的参数名加上一个数字前缀。
至此,通过MindSpore Quantum提供的这些量子线路高阶操作,我们仅用两行代码就构建了所需的Encoder!
[24]:
from mindquantum.utils.show_info import InfoTable
InfoTable('mindquantum', 'scipy', 'numpy')
[24]:
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 14:38:55 2024 |