qml.pulse¶
脉冲编程在各种量子系统中用于对量子操作进行低级控制。应用调谐到特征能量的时变电磁场,导致时变的哈密顿相互作用 \(H(t)\)。在固定时间窗口内使用这样的电磁场驱动系统是一种 脉冲程序。该脉冲程序可以调节以实现用于量子计算的高级门。
该 pulse 模块提供用于模拟量子系统脉冲级控制的函数和类。
它包含一个 ParametrizedHamiltonian 和 ParametrizedEvolution 类,用于描述时间依赖的哈密顿相互作用。 pulse 模块还包括多个方便的函数用于定义脉冲。
该 pulse 模块是为 jax 编写的,无法与PennyLane中通常遇到的其他机器学习框架一起使用。它需要单独安装,详见 jax.readthedocs.io。
有关PennyLane中基本脉冲功能和运行ctrl-VQE示例的演示,请参阅我们的differentiable pulse programming演示。
概述¶
时间演化类¶
|
可调用对象,包含表示参数化哈密顿量的信息。 |
|
参数化演化门,通过将一个 |
便利函数¶
|
返回给定的 |
|
接受一个时间跨度并返回一个可调用对象,用于创建一个在时间上分段常量的函数。 |
|
装饰一个光滑的函数,创建一个分段常数函数来近似它。 |
|
接受一个标量或标量值函数x,并对其应用一个矩形窗口,使得返回的函数在窗口内为x,窗口外为0。 |
硬件兼容的哈密顿量¶
|
返回一个 |
|
返回一个 |
|
返回一个 |
|
返回一个 |
创建参数化的哈密顿量¶
该 pulse 模块提供了一个框架,用于创建如下形式的时间依赖哈密顿量
使用常量运算符 \(H_j\) 和可能依赖于参数 \(p\) 和时间 \(t\) 的标量函数 \(f_j(v_j, t)\)。
定义一个 ParametrizedHamiltonian 需要系数和算符,其中一些系数是可调用的。定义参数化系数的可调用函数必须具有调用签名 (p, t),其中 p 可以是 float、list 或 jnp.array。这些函数应在相关情况下使用 jax.numpy 而不是 numpy 定义。
import pennylane as qml
from jax import numpy as jnp
# defining the coefficients fj(p, t) for the two parametrized terms
f1 = lambda p, t: p * jnp.sin(t) * (t - 1)
f2 = lambda p, t: p[0] * jnp.cos(p[1]* t ** 2)
# defining the operations for the three terms in the Hamiltonian
XX = qml.X(0) @ qml.X(1)
YY = qml.Y(0) @ qml.Y(1)
ZZ = qml.Z(0) @ qml.Z(1)
有两种方法可以从系数和算子构造一个 ParametrizedHamiltonian:
# Option 1
H1 = 2 * XX + f1 * YY + f2 * ZZ
# Option 2
coeffs = [2, f1, f2]
ops = [XX, YY, ZZ]
H2 = qml.dot(coeffs, ops)
警告
通过参数化系数的列表初始化一个 ParametrizedHamiltonian 时,可以使用
lambda 函数迭代地创建多个相同形式的系数列表,即:
coeffs = [lambda p, t: p * t for _ in range(3)]。
在使用列表推导式定义系数时要小心。避免这样做 coeffs = [lambda p, t: p * t**i for i in range(3)],这将只使用最终的索引 i=2 在 lambda 中,因此表现为 coeffs = [(lambda p, t: p * t**2)] * 3。相反,使用 coeffs = [lambda p, t, power=i: p * t**power for i in range(3)]
该ParametrizedHamiltonian是一个可调用的,可以返回一个Operator,如果传递一组参数和一个评估系数的时间\(f_j\)。
>>> H1
(
2 * X(0) @ X(1)
+ <lambda>(params_0, t) * Y(0) @ Y(1)
+ <lambda>(params_1, t) * Z(0) @ Z(1)
)
>>> params = [1.2, [2.3, 3.4]] # f1 takes a single parameter, f2 takes 2
>>> H1(params, t=0.5)
(
2 * (X(0) @ X(1))
+ -0.2876553231625218 * (Y(0) @ Y(1))
+ 1.517961235535459 * (Z(0) @ Z(1))
)
在传递参数时,确保系数函数的顺序和参数的顺序匹配。
当初始化一个 ParametrizedHamiltonian 时,定义有固定系数的项必须在参数化项之前,以防止连线顺序的不一致。
注意
ParametrizedHamiltonian 必须在所有时刻保持厄米特性。这一点不会被显式检查;确保哈密顿量定义正确是用户的责任。
参数化演化¶
在一个跨越时间 \((t_0, t_1)\) 的脉冲程序中,状态根据时间依赖的薛定谔方程演变
实现输入态的单位演化 \(U(t_0, t_1)\),即。
一个 ParametrizedEvolution 是这个解决方案 \(U(t_0, t_1)\) 对于时间依赖的
薛定谔方程的 ParametrizedHamiltonian。
该ParametrizedEvolution类使用数值常微分方程求解器(见jax.experimental.ode)。它可以通过evolve()函数创建:
from jax import numpy as jnp
f1 = lambda p, t: p * jnp.sin(t) * (t - 1)
H = 2 * qml.X(0) + f1 * qml.Y(1)
ev = qml.evolve(H)
>>> ev
ParametrizedEvolution(wires=[0, 1])
初始 ParametrizedEvolution 没有定义参数,因此不会有定义的矩阵。为了获得一个带有矩阵的 Operator,我们必须传递参数和时间间隔:
>>> ev([1.2], t=[0, 4]).matrix()
Array([[-0.14115842+0.j , 0.03528605+0.j ,
0. -0.95982337j, 0. +0.23993255j],
[-0.03528605+0.j , -0.14115842+0.j ,
0. -0.23993255j, 0. -0.95982337j],
[ 0. -0.95982337j, 0. +0.23993255j,
-0.14115842+0.j , 0.03528605+0.j ],
[ 0. -0.23993255j, 0. -0.95982337j,
-0.03528605+0.j , -0.14115842+0.j ]], dtype=complex64)
通过使用不同的输入再次调用ParametrizedEvolution,可以更新参数。
可以通过关键字参数将有关矩阵计算的附加选项传递给ParametrizedEvolution以及参数:
>>> qml.evolve(H)(params=[1.2], t=[0, 4], atol=1e-6, mxstep=1)
ParametrizedEvolution(Array(1.2, dtype=float32, weak_type=True), wires=[0, 1])
可用的关键字参数可以在 ParametrizedEvolution 中找到。如果未指定,它们将默认为预定值。
在 QNode 中使用 qml.evolve¶
可以在QNode中实现ParametrizedEvolution。我们将演化以下ParametrizedHamiltonian:
from jax import numpy as jnp
f1 = lambda p, t: jnp.sin(p * t)
H = f1 * qml.Y(0)
现在我们可以在QNode中执行这个哈密顿哈密顿演变并计算它的梯度:
import jax
jax.config.update("jax_enable_x64", True)
dev = qml.device("default.qubit", wires=1)
@jax.jit
@qml.qnode(dev, interface="jax")
def circuit(params):
qml.evolve(H)(params, t=[0, 10])
return qml.expval(qml.Z(0))
>>> params = [1.2]
>>> circuit(params)
Array(0.96632722, dtype=float64)
>>> jax.grad(circuit)(params)
[Array(2.35694829, dtype=float64)]
我们可以使用装饰器 jax.jit 来即时编译这个执行。这意味着第一次执行通常会花费更多时间,而所有后续的执行将显著更快。
JIT 编译是可选的,当只有单次执行时可以去掉该装饰器。有关即时编译的更多信息,请参见 jax 文档。
警告
要找到两个算子的同时演化,重要的是它们必须包含在同一个 evolve() 中。对于两个不对易的 ParametrizedHamiltonian,应用 qml.evolve(H1)(params, t=[0, 10]) 然后跟随 qml.evolve(H2)(params, t=[0, 10]) 将 不 使这两个脉冲同时作用,尽管时间窗口重叠。相反,它们将在同一时间段内演化,但不考虑 H1 的演化如何影响 H2。
请查看ParametrizedEvolution的使用详情以获取详细示例。