qml.transforms¶
这个子包包含PennyLane变换及其基本构件。
自定义变换¶
qml.transform 可用于定义与 PennyLane QNode 配合使用的自定义变换;此类变换可以将电路映射到一个或多个新电路,并进行相关的经典后处理。
|
概括了一个将带子转换为可以与其他电路类对象(例如 |
转换库¶
在PennyLane中提供了一系列现成可用的变换。
电路编译的变换¶
一组变换以执行基本电路编译任务。
|
通过对量子函数应用一系列变换来编译电路。 |
|
量子函数变换以移除应用在其(自)逆或伴随旁边的任何操作。 |
|
量子变换以将可交换门移动到受控操作的控制和目标量子比特之后。 |
|
量子变换,用于组合依次作用的相同类型的旋转门。 |
|
量子函数变换将一组单量子比特操作融合为一个通用的单量子比特单位操作 ( |
|
量子函数变换用于分解所有单量子位的实例,并选择双量子位 |
量子函数变换以组合作用于不同量子比特的幅度嵌入模板。 |
|
|
量子变换以去除障碍门。 |
|
量子函数变换,通过从右到左运行电路,改变量子比特的位置,从而去除SWAP门。 |
|
量子函数变换以优化给定模式(模板)列表的电路。 |
|
根据期望的耦合图转译电路 |
|
将量子电路分解为用户指定的门集。 |
|
将所有 |
还有一些实用函数和分解可用,它们在更大的PennyLane代码库中帮助进行转换和分解。
|
用于设置自定义分解的上下文管理器。 |
|
应用模式匹配算法并返回最大匹配列表的函数。 |
|
该转换将PennyLane量子磁带转换为PyZX框架中的ZX图。 |
|
将图从 PyZX 转换为 PennyLane 布线,如果该图是类图形的。 |
还有一些实用函数,它们接受一个电路并返回一个有向无环图(DAG)。
|
构建量子电路的成对交换有向无环图 (DAG) 表示。 |
|
表示量子电路的类,作为一个有向无环图(DAG)。 |
|
类,用于存储关于交换DAG节点中量子操作的信息。 |
用于Clifford+T分解的变换¶
该变换接受量子电路,并将其分解为Clifford+T基。
|
将电路分解为Clifford+T基。 |
用于错误缓解的变换¶
|
使用零噪声外推来减轻输入电路。 |
|
全局单元可微电路折叠 |
|
用于多项式拟合的\(f(0)\)外推器。 |
|
多项式拟合,其中多项式的阶数固定为等于 |
|
使用指数模型(\(Ae^{Bx} + C\))推断到零噪声极限。 |
其他变换¶
这些变换使用pennylane.transform()函数/装饰器,可以用于pennylane.tape.QuantumTape和pennylane.QNode。它们有多种用途,如电路预处理、从电路获取信息等。
|
转换 QNode 以支持操作参数的初始批次维度。 |
|
转换电路以支持门输入的初始批量维度。 |
|
在输入电路的指定点插入一个操作。 |
|
根据提供的噪声模型插入操作。 |
|
量子函数变换,它将基于测量结果的操作替换为受控操作。 |
|
将一组测量对角化为标准基底。 |
|
将电路拆分为测量可交换观察量组的带。 |
|
将电路中多项可观察量的期望值分解为单项期望值,以便于不原生支持测量可观察量和的期望值的设备使用。 |
|
将一个广播的胶带扩展为多个胶带,以及一个堆叠和压缩结果的函数。 |
|
将测量一个(可快进的)哈密顿期望值的带分成多个Xi或sgn分解的带,并提供一个函数来重新组合结果。 |
将电路转换为仅具有numpy参数的电路。 |
|
|
应用执行受控版本的 \(\mathcal{Q}\) 单元变换,该变换在 这篇 论文中定义。 |
|
应用变换 量子蒙特卡洛估计 算法。 |
仅对QNodes起作用的变换¶
这些变换只接受QNodes,并返回新的变换函数,用于计算所需的量。
|
从指定的QNode创建一个批处理的部分可调用对象。 |
|
创建一个函数,用于绘制给定的 qnode 或量子函数。 |
|
用matplotlib绘制qnode |
转换开发者函数¶
TransformContainer、TransformDispatcher 和 TransformProgram 是面向开发者的对象,允许创建、调度和组合变换。如果您想要创建自定义变换,请参考qml.transform的文档。
该模块包含变换调度程序和变换容器。 |
|
该模块包含 |
转换电路¶
量子变换是PennyLane中的一个关键概念,指的是将量子电路映射到一个或多个电路,同时伴随一个经典后处理函数。一旦变换在PennyLane中注册,变换后的电路将被执行,经典后处理函数会自动应用于输出。当一个变换生成多个电路时,这变得特别有价值,因为需要一种方法来聚合或减少结果(例如,应用参数移位规则或逐项计算哈密顿量的期望值)。
注意
有关随Pennylane提供的内置变换的示例,请参阅 编译电路文档。
创建您自己的变换¶
为了简化变换的创建并确保它们在PennyLane中各种电路抽象的通用性,提供了pennylane.transform()。
这个装饰器注册接受一个 QuantumTape 作为其主要输入并返回一系列 QuantumTape 及相关处理函数的变换。
为了说明创建量子变换的过程,让我们考虑一个例子。假设我们想要一个变换,它从给定电路中移除所有 RX 操作。在这种情况下,我们只需要过滤原始的 QuantumTape 并返回一个没有被过滤操作的新电路。由于在此场景中我们不需要特定的处理函数,我们包括了一个简单返回第一个且唯一结果的函数。
from pennylane.tape import QuantumScript, QuantumScriptBatch
from pennylane.typing import PostprocessingFn
def remove_rx(tape: QuantumScript) -> tuple[QuantumScriptBatch, PostprocessingFn]:
operations = filter(lambda op: op.name != "RX", tape.operations)
new_tape = tape.copy(operations=operations)
def null_postprocessing(results):
return results[0]
return [new_tape], null_postprocessing
要使您的变换适用于 QNode 和量子函数,您可以使用 pennylane.transform() 装饰器。
dispatched_transform = qml.transform(remove_rx)
对于一个更高级的示例,让我们考虑一个将电路与其伴随相加的变换。我们定义了磁带操作的伴随,创建一个具有这些新操作的新磁带,并返回这两个磁带。
处理函数然后将原始磁带和伴随磁带的结果相加。
在这个示例中,我们使用 qml.transform 作为装饰器来将自定义函数转换为量子变换。
from pennylane.tape import QuantumScript, QuantumScriptBatch
from pennylane.typing import PostprocessingFn
@qml.transform
def sum_circuit_and_adjoint(tape: QuantumScript) -> tuple[QuantumScriptBatch, PostprocessingFn]:
operations = [qml.adjoint(op) for op in tape.operation]
new_tape = tape.copy(operations=operations)
def sum_postprocessing(results):
return qml.sum(results)
return [tape, new_tape], sum_postprocessing
变换的可组合性¶
变换本质上可以在QNode上组合,这意味着可以将具有兼容后处理函数的变换连续应用于QNode。例如,这允许在QNode上应用多个编译过程,以在执行之前最大限度地减少门的数量。
dev = qml.device("default.qubit", wires=1)
@qml.transforms.merge_rotations
@qml.transforms.cancel_inverses
@qml.qnode(device=dev)
def circuit(x, y):
qml.Hadamard(wires=0)
qml.Hadamard(wires=0)
qml.RX(x, wires=0)
qml.RY(y, wires=0)
qml.RZ(y, wires=0)
qml.RY(x, wires=0)
return qml.expval(qml.Z(0))
在这个例子中,反向被抵消,从而去除了两个Hadamard门。随后,旋转被合并为一个单一的 qml.Rot 门。因此,两个变换成功应用于电路。
将参数传递给变换¶
我们可以通过 @partial(transform_fn, **transform_kwargs) 装饰一个 QNode,以提供额外的关键字参数给转换函数。在下面的示例中,我们将关键字参数 grouping_strategy="wires" 传递给 split_non_commuting() 量子转换,该转换将电路拆分为测量交换可观测量组的带。
from functools import partial
dev = qml.device("default.qubit", wires=2)
@partial(qml.transforms.split_non_commuting, grouping_strategy="wires")
@qml.qnode(dev)
def circuit(params):
qml.RX(params[0], wires=0)
qml.RZ(params[1], wires=1)
return [
qml.expval(qml.X(0)),
qml.expval(qml.Y(1)),
qml.expval(qml.Z(0) @ qml.Z(1)),
qml.expval(qml.X(0) @ qml.Z(1) + 0.5 * qml.Y(1) + qml.Z(0)),
]