更新的操作符¶
在PennyLane的版本0.36中,我们更改了一些操作符及其之间的算术运算的后台处理方式。这实现了几个目标:
让使用PennyLane运算符和使用笔和纸一样简单。
提高运算符算术的效率。
在许多情况下,这些变化不应导致代码出现问题,且与以前版本的差异可能不明显。
此页面提供有关运算符算术更新的附加详细信息,并可用于排查受影响用户的问题。
更新摘要¶
经过一段时间的弃用,运算符的遗留行为在PennyLane版本0.40中被移除。 使用最新PennyLane的任何人将自动使用更新的运算符算术。 理想情况下,您的代码在进行此更新时不应出现崩溃。 如果仍然出现,可能只需要一些小的更改。 为此,请参阅故障排除部分。 如果您使用了任何明确提供的函数以继续使用被弃用的行为,如qml.operation.disable_new_opmath(),该代码将需要被移除。
执行算术运算的底层系统已被更改。可以使用标准的Python操作符进行算术运算,如
+,*和@,或者通过位于op_math的算术函数。您现在可以通过
I,X,Y, 和Z轻松访问 Pauli 运算符。>>> from pennylane import I, X, Y, Z >>> X(0) X(0)
原始的长名称
Identity,PauliX,PauliY, 和PauliZ仍可用,且在功能上等同于I,X,Y, 和Z,但是现在推荐使用短名称。PennyLane中的算子可以具有后端的Pauli表示,这可以用来执行更快速的算子运算。现在,当可用时,Pauli表示将自动用于计算。您可以在可用时访问任何算子的
pauli_rep属性。>>> op = X(0) + Y(0) >>> op.pauli_rep 1.0 * X(0) + 1.0 * Y(0) >>> type(op.pauli_rep) pennylane.pauli.pauli_arithmetic.PauliSentence
您可以通过
operation()方法将PauliSentence转换回适当的Operator。>>> op.pauli_rep.operation() X(0) + Y(0)
对PennyLane算子的字符串表示进行了大量改进,使其更短,并可以复制粘贴为有效的PennyLane代码。
>>> 0.5 * X(0) 0.5 * X(0) >>> 0.5 * (X(0) + Y(1)) 0.5 * (X(0) + Y(1))
包含多个项的和被分成多行,但仍然可以复制回来作为有效的代码:
>>> 0.5 * (X(0) @ X(1)) + 0.7 * (X(1) @ X(2)) + 0.8 * (X(2) @ X(3)) ( 0.5 * (X(0) @ X(1)) + 0.7 * (X(1) @ X(2)) + 0.8 * (X(2) @ X(3)) )
技术细节
旧系统和新系统之间的变化主要涉及 Python 运算符 + - * / @,现在创建以下 Operator 子类实例。
旧版 |
更新后的运算符 |
|
|---|---|---|
张量积
|
|
|
总和
|
|
|
标量积
|
|
|
|
|
|
|
|
|
|
不适用 |
|
三个主要的新 opmath 类 SProd、Prod 和 Sum 已经存在了一段时间。比如,dot() 一直返回一个 Sum 实例。
使用方法
除了python操作符,你还可以使用构造函数 s_prod()、prod() 和 sum()。对于复合操作符,我们可以通过 op.operands 属性访问它们的组成部分。
>>> op = qml.sum(X(0), X(1), X(2))
>>> op.operands
(X(0), X(1), X(2))
如果所有术语都是由具有有效 pauli_rep 的算子组成,那么复合算子在 PauliSentence 实例的意义上也具有有效的 pauli_rep。这通常对于快速算术处理很有用。
>>> op.pauli_rep
1.0 * X(0)
+ 1.0 * X(1)
+ 1.0 * X(2)
此外,复合运算符可以使用 simplify() 或 op.simplify() 方法简化。
>>> op = 0.5 * X(0) + 0.5 * Y(0) - 1.5 * X(0) - 0.5 * Y(0) # no simplification by default
>>> op.simplify()
-1.0 * X(0)
>>> qml.simplify(op)
-1.0 * X(0)
请注意,简化从不在原地发生,因此原始操作符保持不变。
>>> op
(
0.5 * X(0)
+ 0.5 * Y(0)
+ -1 * 1.5 * X(0)
+ -1 * 0.5 * Y(0)
)
我们经常对获取系数和 纯 算子列表感兴趣。我们可以通过使用 op.terms() 方法来实现。
>>> op = 0.5 * (X(0) @ X(1) + Y(0) @ Y(1) + 2 * Z(0) @ Z(1)) - 1.5 * I() + 0.5 * I()
>>> op.terms()
([0.5, 0.5, 1.0, -1.0], [X(1) @ X(0), Y(1) @ Y(0), Z(1) @ Z(0), I()])
从这个例子可以看出,这个方法已经处理了算术简化。
qml.哈密顿量
类 Tensor 和 Hamiltonian 已被移除。熟悉的 qml.Hamiltonian 仍然可以使用,它会调度到 LinearCombination,并提供相同的用法和功能,但实现细节不同。
>>> import pennylane as qml
>>> from pennylane import X
>>> H = qml.Hamiltonian([0.5, 0.5], [X(0), X(1)])
>>> type(H)
pennylane.ops.op_math.linear_combination.LinearCombination
故障排除¶
如果您在使用早期版本的PennyLane时存在有效代码,您可能会在版本v0.36及以上中遇到PennyLane更新的算子算术问题。为了帮助识别解决方案,请选择下面描述您情况的选项。
我以前的PennyLane脚本不再运行了
我们建议进行以下检查:
检查是否明确使用了遗留的
Tensor类。如果在你的脚本中找到它,可以将Tensor(*terms)更改为qml.prod(*terms),调用签名保持不变。检查显式使用
op.obs属性的情况,其中op是某个操作符。这是访问Tensor实例中张量积项的方式。请改用op.operands。op = X(0) @ X(1) assert op.operands == (X(0), X(1))
检查对
qml.ops.Hamiltonian的显式使用。在这种情况下,只需更改为qml.Hamiltonian。 这将分派到LinearCombination类,它提供相同的 API 和功能 但实现细节不同。
如果由于某些意想不到的原因您的脚本仍然出错,请在PennyLane 讨论论坛上发帖或在PennyLane GitHub页面上提交错误报告。
有关qml.Hamiltonian调度的要点
该LinearCombination的API与已移除的qml.ops.Hamiltonian的API几乎相同。
一个小的区别是 Hamiltonian.simplify() 不再在原地改变实例。相反,你必须执行
以下:
>>> H1 = qml.Hamiltonian([0.5, 0.5], [X(0) @ X(1), X(0) @ X(1)])
>>> H1 = H1.simplify()
关于新 opmath 实例的嵌套结构的简要说明
最终操作符的类型由最外层的操作决定。结果对象是一个嵌套结构(和的积/积的和或积的和的积)。
>>> op = 0.5 * (X(0) @ X(1)) + 0.5 * (Y(0) @ Y(1))
>>> type(op)
pennylane.ops.op_math.sum.Sum
>>> op.operands
(0.5 * (X(0) @ X(1)), 0.5 * (Y(0) @ Y(1)))
>>> type(op.operands[0]), type(op.operands[1])
(pennylane.ops.op_math.sprod.SProd, pennylane.ops.op_math.sprod.SProd)
>>> op.operands[0].scalar, op.operands[0].base, type(op.operands[0].base)
(0.5, X(0) @ X(1), pennylane.ops.op_math.prod.Prod)
我们可以构造一个具有不同嵌套结构的等效操作符。
>>> op = (0.5 * X(0)) @ X(1) + (0.5 * Y(0)) @ Y(1)
>>> op.operands
((0.5 * X(0)) @ X(1), (0.5 * Y(0)) @ Y(1))
>>> type(op.operands[0]), type(op.operands[1])
(pennylane.ops.op_math.prod.Prod, pennylane.ops.op_math.prod.Prod)
>>> op.operands[0].operands
(0.5 * X(0), X(1))
>>> type(op.operands[0].operands[0]), type(op.operands[0].operands[1])
(pennylane.ops.op_math.sprod.SProd,
pennylane.ops.qubit.non_parametric_ops.PauliX)
还有另一种构造相同等效算符的方法。
我们可以通过使用 op.simplify() 将它们都带到同样的格式,从而将算符简化为
\(\sum_i c_i \hat{O}_i\) 的形式,其中 \(c_i\) 是一个标量系数,而 \(\hat{O}_i\) 是一个
纯算符或算符的张量积。
>>> op1 = 0.5 * (X(0) @ X(1)) + 0.5 * (Y(0) @ Y(1))
>>> op2 = (0.5 * X(0)) @ X(1) + (0.5 * Y(0)) @ Y(1)
>>> op3 = 0.5 * (X(0) @ X(1) + Y(0) @ Y(1))
>>> qml.equal(op1, op2), qml.equal(op2, op3), qml.equal(op3, op1)
(True, False, False)
>>> op1 = op1.simplify()
>>> op2 = op2.simplify()
>>> op3 = op3.simplify()
>>> qml.equal(op1, op2), qml.equal(op2, op3), qml.equal(op3, op1)
(True, True, True)
>>> op1, op2, op3
(0.5 * (X(1) @ X(0)) + 0.5 * (Y(1) @ Y(0)),
0.5 * (X(1) @ X(0)) + 0.5 * (Y(1) @ Y(0)),
0.5 * (X(1) @ X(0)) + 0.5 * (Y(1) @ Y(0)))
我们也可以通过 op.terms() 方法获得这些标量系数和张量积算子。
>>> coeffs, ops = op1.terms()
>>> coeffs, ops
([0.5, 0.5], [X(1) @ X(0), Y(1) @ Y(0)])