# PennyLane：设备选项与支持的操作

使用 PennyLane 时，先选定平台设备，再为这台设备设置 configuration_data。你可以查看它公开的门、连接关系和编译选项，也可以查看插件本身支持的 PennyLane 算子。本章展示这两类查询，并把查询结果用于一个 128-shots Bell 线路的报价。

插件会将 QNode 的线路转换为逻辑 OpenQASM 2，再通过平台提交。本章先查询设备信息，再用选定的设备和配置准备 Bell 实验的报价；代码块按顺序运行。

- [先看一条 Bell 实验的完整执行流程](pennylane.html)
- [查阅操作、测量、shots 展开和梯度示例](pennylane-measurements.html)

本例创建默认使用 OPEN 的 scheduler，设备继承 scheduler.currency。需要 FULL 时，在创建客户端时传 currency="FULL"；独立创建 qml.device 时也可直接选择钱包。用 dev.currency 查看当前选择，准备报价后可查看本次金额与币种。

## 开始前：选择设备并读取详情

先安装 pennylane 扩展，按“连接与认证”章节配置平台地址、Client ID 和 Client Secret。将目标设备的 short_code 保存到 QUANTUM_SOURCE_BACKEND，例如设备目录中的 origin:WK_C180，下面的代码会读取该设置。

```python
import os
import pennylane as qml
from quantum_source_sdk import SchedulerClient

api_url = os.environ["QUANTUM_SOURCE_API_URL"]
backend_code = os.environ["QUANTUM_SOURCE_BACKEND"]
scheduler = SchedulerClient(base_url=api_url)

# 读取所选设备的详情和配置字段。
details = scheduler.get_backend_class(backend_code)
schema = details.configuration_schema
properties = schema.get("properties", {})

print("设备：", details.short_code, details.name)
print("类型、状态：", details.type, details.status)
print("比特数：", details.num_qubits)
print("可接收格式：", details.supported_formats)
print("平台未结束任务数：", details.platform_active_tasks)
print("设备可配置字段：")
for name, definition in properties.items():
    print({
        "name": name,
        "type": definition.get("type"),
        "enum": definition.get("enum"),
        "default": definition.get("default", "未声明"),
        "description": definition.get("description", ""),
    })

# 创建设备对象，手动查看报价后确认执行。
dev = qml.device(
    "quantum_source.device",
    wires=2,
    backend=backend_code,
    scheduler=scheduler,
    auto_confirm=False,
)
caps = dev.provider_capabilities
print("平台声明的功能：", dev.features)
print("逻辑输入门：", sorted(caps.supported_gate_names))
print("原生门：", sorted(caps.native_gate_names))
print("连接关系：", caps.topology.coupling_map)
print("可用物理比特：", caps.available_qubits)
print("timing：", dict(caps.timing))
print("noise：", dict(caps.noise))
```

| 示例中的调用 | 作用 | 返回值或使用位置 |
| --- | --- | --- |
| scheduler.get_backend_class(backend_code) | 读取这台设备在平台上的详情 | BackendClassRead；用 configuration_schema 查看可选参数 |
| qml.device("quantum_source.device", ...) | 创建绑定目标设备的 PennyLane 插件对象 | dev；随后可用于 @qml.qnode(dev) |
| dev.provider_capabilities | 读取门、拓扑和其他硬件能力 | BackendCapabilities；下文以 caps 引用 |
| wires=2 | 声明本次 PennyLane 线路有两个逻辑 wire | 逻辑编号为 0、1，物理位置由厂商映射 |
| scheduler=scheduler | 复用已经建立的客户端和平台认证 | 设备沿用该客户端的连接与钱包 |
| auto_confirm=False | 采用手动批准报价的流程 | 先 prepare 查看报价，再 confirm 执行 |

本段读取两类信息：get_backend_class 返回设备目录详情，provider_capabilities 首次访问时查询并缓存插件所用的能力对象。插件按线路宽度和当前设备状态检查可用性；查看离线设备等目录信息时，可直接使用 get_backend_class。

继续后面的示例时，保留 scheduler 连接。完成本页操作后，调用 dev.close() 和 scheduler.close() 关闭连接。

## 选择正确的查询入口

查询线路操作时看 capabilities，查询设备编译选项时看 configuration_schema。下表给出各类信息的读取入口。

| 想查的内容 | 入口和返回类型 | 如何使用 |
| --- | --- | --- |
| PennyLane 算子和测量支持 | dev.capabilities → DeviceCapabilities | 查看 operations、observables、measurement_processes，帮助编写 QNode |
| 目标设备的门、比特和拓扑 | dev.provider_capabilities → BackendCapabilities | 查看 supported_ops、native_ops、topology、timing、noise、features |
| 目标设备提供的可选参数 | details.configuration_schema → Mapping | 查看 properties 中的类型、允许值、默认值与说明 |
| 自己为设备设置的参数 | dev.configuration_data → dict | 检查准备下一批次时使用的显式配置 |

设备 schema 从 details.configuration_schema 读取，选择好的厂商参数放入 qml.device 的 configuration_data。dev.capabilities 则用于查看 PennyLane 算子与测量支持。

| 需求 | 使用方式 | 得到什么 |
| --- | --- | --- |
| 查询 mapping / optimization 等选项 | scheduler.get_backend_class(backend_code).configuration_schema | 设备字段的类型、允许值和默认值 |
| 为后续实验设置厂商选项 | qml.device(..., configuration_data={"mapping": True}) | 采用指定配置的设备对象 |
| 先看线路报价 | tape = qnode.construct(args, kwargs)，然后 dev.prepare(tape) | 保存线路与报价的准备对象 |
| 固定硬件物理编号 | 使用 Qiskit 物理布局或 Core 物理输入流程 | 按指定物理位置准备实验 |

## 发现设备专属选项

properties 的每个键对应一个设备选项。例如 mapping 的类型为 boolean、允许值包含 True 时，可以设置 configuration_data={"mapping": True}。在这里查看目标设备提供的选项，再按自己的实验需求选择。

| schema 内容 | 应怎样理解 | 使用注意 |
| --- | --- | --- |
| properties | 设备提供的可配置字段集合 | 从这些字段中选择要调整的选项。 |
| type | JSON 值类型，例如 boolean、integer、number、string、array、object | boolean 使用 Python True / False，其他字段按类型填写。 |
| enum / const | 允许值集合 / 固定值 | 从 enum 中选择，或采用 const 指定的值。 |
| default | 设备声明的默认值 | 显式设置的值可通过 dev.configuration_data 查看。 |
| minimum / maximum 等 | 字段数值范围 | 在返回的范围内填写数值。 |
| description / title | 字段用途或显示名称 | 结合说明选择适合实验的配置。 |
| required | schema 声明的必需字段（若存在） | 准备任务时提供这些字段，由平台检查完整配置。 |

本源真机的常见选项包括 mapping、optimization 和 amend，分别用于云端拓扑映射、线路优化和厂商修正功能。mapping 将逻辑线路适配到设备连接关系。查看本次设备返回的字段说明后，将需要的选项写入 configuration_data；空 properties 表示当前设备未公开可调选项。

准备任务时，SDK 与平台会检查设备选项，并将配置和线路一同交给目标设备。用户只需提供所选字段和值。

## 设备能力属性

用 caps 查看设备信息。编写逻辑线路时可先关注支持操作和 shots 范围；研究硬件时，再查看 native_gates、连接图以及 timing、noise。

| 读取方式 | Python 类型 | 可回答的问题与限制 |
| --- | --- | --- |
| caps.num_qubits / caps.n_qubits | int 或 None | 设备比特数；None 表示未提供。 |
| caps.supported_gates / caps.supported_ops | tuple[GateSpec, ...] | 逻辑输入操作描述。 |
| caps.native_gates / caps.native_ops | tuple[GateSpec, ...] | 物理原生操作描述。 |
| gate.name、gate.arity、gate.parameters、gate.qargs | str、int、tuple[str, ...]、tuple 或 None | 门名、作用比特数、参数名及可选的放置范围。 |
| caps.topology.coupling_map、caps.topology.directed | tuple[tuple[int, int], ...]、bool | 硬件连接关系及方向性。 |
| caps.available_qubits | tuple[int, ...] | 平台目录提供的可用物理位置集合。 |
| caps.max_shots、caps.limits | int 或 None、dict | 设备执行的 shots 等限制。 |
| caps.features / dev.features | frozenset[str] / list[str] | 平台声明的功能标签，配合插件操作支持使用。 |
| caps.timing、caps.noise | Mapping[str, Any] | 可选的时间与噪声信息；空字典表示当前未提供数据。 |

```python
# 逐项查看原生门数据。
for gate in caps.native_gates:
    print({
        "name": gate.name,
        "arity": gate.arity,
        "parameters": gate.parameters,
        "qargs": gate.qargs,
    })

print("厂商是否声明 reset：", dev.allows_reset())
print("厂商是否声明中途测量：", dev.allows_mid_circuit_measure())
print("厂商是否声明动态线路：", dev.allows_dynamic_circuits())
print("厂商是否声明某个功能：", dev.supports_feature("custom_gates"))
```

allows_* 与 supports_feature 返回平台的功能声明：True 表示已声明，False 表示当前没有相应声明。编写 QNode 时，配合下面的插件操作和测量支持使用。

## PennyLane 支持的操作与测量

dev.capabilities 描述可在 QNode 中使用的操作与测量。下面读取安装包附带的插件声明，帮助选择 PennyLane 写法。

```python
# 查看 PennyLane 插件提供的操作与测量。
plugin_caps = dev.capabilities
print("插件操作名：", sorted(plugin_caps.operations))
print("插件可观察量：", sorted(plugin_caps.observables))
print("插件测量类型：", sorted(plugin_caps.measurement_processes))
print("插件支持的中途测量方法：", plugin_caps.supported_mcm_methods)
```

| 操作类别 | 当前插件声明的常用 PennyLane 操作 | 代码中的用途 |
| --- | --- | --- |
| 无参数单比特门 | qml.PauliX、qml.PauliY、qml.PauliZ、qml.Hadamard、qml.S、qml.T、qml.SX、qml.Identity | 改变单个逻辑 wire 的状态 |
| 参数化单比特门 | qml.RX、qml.RY、qml.RZ、qml.PhaseShift | 以角度参数构造可调线路 |
| 双比特门 | qml.CNOT、qml.CY、qml.CZ、qml.CH、qml.SWAP | 在两个逻辑 wire 上操作；实际物理映射由对应执行路径处理 |
| 受控旋转 | qml.CRX、qml.CRY、qml.CRZ、qml.ControlledPhaseShift | 向受控操作提供角度参数 |
| 三比特门 | qml.Toffoli、qml.CSWAP | 描述三比特操作；后续编译可以继续分解 |

| 测量写法 | 结果形状或含义 | 使用要点 |
| --- | --- | --- |
| qml.counts(wires=[0, 1]) | 位串到计数的字典 | 本章 Bell 示例使用；指定有限 shots |
| qml.probs(wires=[0, 1]) | 所选逻辑 wires 的概率数组 | 按计算基位串顺序读取概率值 |
| qml.expval(qml.PauliZ(0)) | 一个可观察量的期望值 | 不同测量基可能使任务展开成多条线路 |
| qml.var(qml.PauliZ(0)) | 可观察量的方差 | 使用有限 shots 估计 |
| qml.sample(...) | 样本形式的结果 | 按测量要求返回与计数频数一致的样本 |

当前插件面向末尾测量的静态线路，提供常见门、有限 shots 的 counts/sample/expval/var 和 probs 入口。PennyLane 会先分解可处理的高级操作与测量，再生成逻辑线路；timing/noise 用于查看硬件数据。

编写线路后调用 prepare，SDK 和平台会完成预处理与设备检查，并返回本次实验的报价。

## 使用 configuration_data 设置设备选项

创建 qml.device 时，通过 configuration_data 设置设备选项。下面沿用上文的 scheduler、backend_code 和 properties，为提供 mapping 的设备开启逻辑映射，并填写任务所属的组织 ID。

```python
configuration = {}
if "mapping" in properties:
    configuration["mapping"] = True

configured_dev = qml.device(
    "quantum_source.device",
    wires=2,
    backend=backend_code,
    scheduler=scheduler,
    organization_id=os.environ["QUANTUM_SOURCE_ORGANIZATION_ID"],
    configuration_data=configuration,
    auto_confirm=False,
)
print("本设备显式配置：", configured_dev.configuration_data)
```

本段创建 configured_dev，供后面的 Bell QNode 使用。backend 选择同一台已经查询过的设备，organization_id 决定任务归属，configuration_data 保存本次选择的厂商选项。代码只在 schema 中存在 mapping 时填写它；没有需要调整的设备选项时，也可以传空字典或省略 configuration_data。

本例使用允许 mapping=True 的逻辑线路配置。要继续设置 optimization 或 amend，将设备 properties 中提供的这些字段放在同一层 configuration_data 字典中。

需要改变后续任务的配置时，更新 configured_dev.configuration_data，例如将设备提供的 optimization 设为 False。设备会保存构造时配置的副本；每次 prepare 再保存该批次采用的配置和报价。多个实验使用不同设置时，也可分别创建设备对象。

## 更新后续实验的配置

设备配置作用于随后准备的批次。为另一组配置创建新的 qml.device，或在下一次 prepare 前更新 configuration_data；已有 prepared 继续使用准备时保存的配置和报价。

| 操作 | 当前 PennyLane 插件的行为 |
| --- | --- |
| qml.device(..., configuration_data={...}) | 设置本设备后续准备使用的平铺配置；这是公开的主要设备选项入口。 |
| 更改 dev.configuration_data 后再次 prepare | 使用更新后的设备配置生成新的报价。 |
| 使用已有 prepared | 沿用该批次准备时保存的配置和报价。 |

prepare(tape) 接收线路；设备选项统一从 dev.configuration_data 读取。框架执行流程使用的 PennyLane ExecutionConfig 保留在框架层。

## 示例：构造 Bell 线路并查看报价

给 QNode 声明 128 shots，用 Hadamard 和 CNOT 制备 Bell 线路，再选择 counts 测量。使用 construct() 取得线路，将其交给 configured_dev.prepare() 查看报价。

```python
@qml.set_shots(128)
@qml.qnode(configured_dev, diff_method=None)
def bell():
    qml.Hadamard(wires=0)
    qml.CNOT(wires=[0, 1])
    return qml.counts(wires=[0, 1])

# construct 创建用于准备报价的 tape。
tape = bell.construct((), {})
prepared = configured_dev.prepare(tape)

print(type(prepared).__name__)
print("实际展开任务数：", prepared.task_count)
print("本批次总 shots：", prepared.total_shots)
print("报价：", prepared.total_amount, prepared.currency)
print("报价有效期：", prepared.expires_at_utc)
print("准备使用的逻辑 OpenQASM：")
for program in prepared.programs:
    print(program)

# 查看以上报价后，可继续主教程的确认执行步骤。
```

### 返回值：PreparedPennyLaneBatch

| 返回属性 | 解释 |
| --- | --- |
| task_count | 这一次准备实际展开的厂商线路数 |
| total_shots | 所有展开线路请求的 shots 总和 |
| total_amount / currency | 本批次总报价及币种 |
| expires_at_utc | 本批次报价有效期，使用 UTC 表示 |
| programs | 实际准备报价使用的逻辑 OpenQASM 程序，可用于检查转换结果 |

返回对象是 PreparedPennyLaneBatch：quote 保存本批次报价，programs 保存用于报价的逻辑 QASM 文本。本例包含一个 counts 测量；广播、不同测量基和梯度可能展开为多条任务，可通过 task_count 和 total_shots 查看实际工作量。

prepare 完成预处理、上传和报价。核对报价后，按 PennyLane 主教程的确认步骤执行实验并读取结果。

## 逻辑 wires 与物理比特

PennyLane 的 wires 是逻辑标签。插件生成 QASM 时会按 wire 顺序编号为 q[0]、q[1]……，再由云端进行拓扑映射，将逻辑线路适配到设备连接关系。例如 wires=["a", "b"] 表示两个逻辑 wire。需要指定硬件位置时，使用下面的物理布局入口。

| 用户目的 | 应使用的方式 |
| --- | --- |
| 通过本源云端拓扑映射适配设备连接关系 | 设备提供 mapping 时使用 mapping=True，或采用设备默认逻辑配置。 |
| 固定物理比特 1–11、避开 0 号比特 | 使用 Qiskit 的 physical_qubits 或 initial_layout 编译布局。 |
| 直接提交自己写好的物理程序 | 按照 Core 物理输入流程准备程序和配置。 |

## 门分解与 OpenQASM 转换

插件自动将 PennyLane 操作与测量转换成逻辑线路。序列化器依据 supported_ops / supported_gates 输出设备可接收的门，并为可转换的其他门生成等价定义；物理映射由厂商完成。

例如设备声明逻辑 rx 时，可直接输出 rx(theta)；需要等价表示时则生成 qs_rx 门定义。查看 prepared.programs，可以了解此次准备实际使用的 OpenQASM。

用户继续使用 PennyLane 算子编写线路即可。高级操作的分解、逻辑 QASM 表示和厂商原生门转换由插件与平台完成。

## 更新设备信息与关闭连接

dev.provider_capabilities 在当前设备实例中缓存首次读取的能力。需要重新读取平台目录时，调用 scheduler.get_backend_class(backend_code)；要按新数据准备实验，创建新的设备实例。平台按自己的刷新策略更新目录。

timing、noise、qargs 和 description 等可选字段为空时，显示为“未提供”即可。普通逻辑线路可继续采用设备提供的默认配置。

```python
# 完成本页操作后关闭本地连接。
dev.close()
configured_dev.close()
scheduler.close()
```

## API 参考

设备对象的构造参数、能力属性、配置选项和准备方法集中收录在 PennyLane API 参考中。

- [PennyLane 设备与准备对象 API](api.html#pennylane)
- [BackendCapabilities 与能力查询](api.html#capabilities)
- [接口实现与测试依据](api.html#evidence)
- [返回 PennyLane 使用流程](pennylane.html)
- [PennyLane 测量、shots 与梯度详解](pennylane-measurements.html)
- [Qiskit 的设备能力与 Options](capabilities-qiskit.html)
- [Core 的设备详情与配置 schema](capabilities-core.html)
- [连接与认证](connection.html)

## 下载本页 Jupyter Notebook

收录本页 Python 示例与说明，便于在 Jupyter Notebook 中学习和运行；安装命令保留为说明。

[下载《设备选项与支持范围》Notebook（.ipynb）](../../notebooks/sdk_user_guide_capabilities_pennylane.ipynb)
