Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ pyqpanda-algorithm 是由本源量子(Origin Quantum)开发的量子算法
- **SparseAmp(稀疏幅度编码)**
高效将稀疏向量编码为量子态,减少量子资源消耗,适用于数据预处理。

- **QShadow(可观测量感知的经典阴影)**
通过局域偏置 Pauli 测量从同一批样本估计多个可观测量,并提供同时置信区间与测量预算控制。

------

## 安装
Expand Down
2 changes: 2 additions & 0 deletions README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ Provides underlying tools for quantum computing workflows.
Implements numerical comparison or threshold judgment to build quantum decision logic.
- **SparseAmp (Sparse Amplitude Encoding)**
Efficiently encodes sparse vectors into quantum states, reducing quantum resource consumption (for data preprocessing).
- **QShadow (Observable-Aware Classical Shadows)**
Estimates many observables from locally biased Pauli measurements with simultaneous confidence intervals and explicit shot-budget control.

------

Expand Down
96 changes: 96 additions & 0 deletions Tutorials/source/QShadow.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
QShadow:可观测量感知的经典阴影
====================================

QShadow 从同一批局域 Pauli 测量中估计多个可观测量。它适合变分算法能量读出、
相关函数扫描和小规模真机实验的测量后处理。经典阴影与局域偏置方法是已有研究;
本模块的 PyQPanda3 集成、带下限规划器、置信预算流程和测试为独立实现。

基本工作流
----------

.. code-block:: python

from pyqpanda_alg.QShadow import (
PauliObservable,
optimize_basis_probabilities,
sample_measurement_plan,
simulate_pauli_measurements,
estimate_observables,
)

targets = [
PauliObservable.from_terms(
{"ZZ": -1.0, "XI": 0.2, "IX": 0.2}, name="energy"
),
PauliObservable.from_terms({"ZI": 1.0}, name="magnetisation"),
]
result = optimize_basis_probabilities(targets, probability_floor=0.03)
plan = sample_measurement_plan(result.probabilities, 5000, seed=7)
data = simulate_pauli_measurements([1, 0, 0, 0], plan, seed=8)
estimates = estimate_observables(data, targets, family_confidence=0.95)

约定与无偏性
------------

Pauli 字符串和数据集统一使用 q0-first:``"XI"`` 表示 X 作用于 q0。对目标 Pauli
项,只有测量基覆盖其非恒等支撑时,该 shot 才产生非零贡献;贡献除以对应测量基
概率的乘积。数据集保存每个 shot 的完整 X/Y/Z 概率,因此不同规划轮次可以无偏
合并。

规划器优化的是系数加权的对角二阶矩代理,并通过 ``probability_floor`` 防止某个
基完全不可观测及逆倾向权重发散。代理损失下降不是任意未知态上实际方差下降的
保证。

离线重复基准
--------------

``example/QShadow/qshadow_planning_benchmark.py`` 使用固定状态、可观测量和种子,
对均匀规划与 QShadow 规划进行 1000 轮、每轮 2000 shots 的对照。规划损失从
``24.54`` 降至 ``5.964549``,聚合 RMSE 降低 ``60.20%``,两个可观测量的平均
区间半宽分别降低 ``62.35%`` 和 ``53.42%``。在另一个 100 轮顺序预算实验中,
达到 ``0.22`` 目标半宽所需平均 shots 从 ``7284.9`` 降至 ``1892.8``,减少
``74.02%``,且没有硬上限违规。

两种方案在该配置中的单项和 family-wise 经验覆盖率均为 ``1.000``,说明区间较
保守,不表示精确 95% 校准。结果只适用于该固定基准,不构成所有状态与可观测量上
普遍优势的声明。

置信预算
--------

``ShadowBudgetController`` 用 Bonferroni 同时经验 Bernstein 半宽决定下一批 shots,
同时遵守 ``max_shots``。它只返回建议,不自动提交任务。远程执行还可通过
``run_measurement_plan(..., max_jobs=N)`` 在任何任务提交前限制唯一测量线路数量。

真机结果必须同时报告设备/后端、时间、shots、任务 ID、原始 counts、采样概率、
统计区间及理想模拟器偏差。当前实现不含读出误差缓解,因此经验 Bernstein 区间
不覆盖硬件系统偏差。

WK_C180 实测证据
----------------

2026-07-26 的最小验证在 ``WK_C180`` 上执行 X/Y/Z 各 512 shots,总计恰好
3 个任务、1536 shots,且没有自动重试。真实 counts 经 q0-first 转换后进入同一个
QShadow 数据集,按逐 shot 的 ``(1/3, 1/3, 1/3)`` 概率同时估计 X/Y/Z,并生成
family-wise 经验 Bernstein 区间。机器可读证据位于
``example/QShadow/qshadow_wukong_validation_20260726.json``,配套解释位于同目录
``qshadow_wukong_validation_20260726.md``。

这次运行验证了从真实后端 counts 到同时估计、置信区间和 3-job/1536-shot 预算的
完整工作流。硬件 X/Y/Z 区间均未覆盖理想值,Bloch 向量范数为
``1.539826 > 1``;本次平台配置包含 ``is_amend=True``,QShadow 未执行读出误差
缓解,因此不把结果解释为硬件精度成功。由于 X/Y/Z 目标完全对称并采用均匀计划,
本实验也不比较偏置规划器与均匀规划的真机优势;规划器行为由 CPUQVM 示例和测试
覆盖。

引用
----

* Huang, Kueng, Preskill, *Predicting many properties of a quantum system from
very few measurements*, Nature Physics 16 (2020), arXiv:2002.08953.
* Hadfield, Bravyi, Raymond, Mezzacapo, *Measurements of Quantum Hamiltonians
with Locally-Biased Classical Shadows*, arXiv:2006.15788.
* Hadfield, *Adaptive Pauli Shadows for Energy Estimation*, arXiv:2105.12207.

完整 API、云后端安全示例、限制和原创性边界见
``pyqpanda_alg/QShadow/README.md``。
7 changes: 7 additions & 0 deletions Tutorials/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ Overall, it provides a standardized set of tools for developers, allowing them t

Changelog

.. toctree::
:maxdepth: 2
:caption: QShadow Tutorial

QShadow

.. toctree::
:caption: API Reference
:maxdepth: 2
Expand All @@ -42,3 +48,4 @@ Overall, it provides a standardized set of tools for developers, allowing them t
autoapi/pyqpanda_alg/QSVD/index
autoapi/pyqpanda_alg/QSVR/index
autoapi/pyqpanda_alg/QUBO/index
autoapi/pyqpanda_alg/QShadow/index
106 changes: 106 additions & 0 deletions pyqpanda-algorithm/example/QShadow/qshadow_observable_estimation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
"""QShadow end-to-end example: planning, CPUQVM sampling, and confidence budget."""

from __future__ import annotations

from pyqpanda3.core import CNOT, CPUQVM, QCircuit, QProg, RY

from pyqpanda_alg.QShadow import (
PauliObservable,
PyQPandaRunner,
ShadowBudgetController,
estimate_observables,
optimize_basis_probabilities,
planning_loss,
run_measurement_plan,
sample_measurement_plan,
uniform_probabilities,
)


def prepare(qubits):
"""A reproducible three-qubit entangled state-preparation circuit."""

return (
QCircuit()
<< RY(qubits[0], 0.7)
<< RY(qubits[1], -0.4)
<< RY(qubits[2], 0.3)
<< CNOT(qubits[0], qubits[1])
<< CNOT(qubits[1], qubits[2])
)


def exact_statevector():
program = QProg(3)
program << prepare(program.qubits())
machine = CPUQVM()
machine.run(program, shots=1)
return machine.result().get_state_vector()


def main():
observables = [
PauliObservable.from_terms(
{
"ZZI": -1.0,
"IZZ": -0.8,
"XII": 0.20,
"IXI": 0.15,
"IIX": 0.10,
},
name="structured_energy",
),
PauliObservable.from_terms(
{"ZIZ": 1.0, "XXI": 0.25}, name="long_range_order"
),
]

uniform = uniform_probabilities(3)
optimisation = optimize_basis_probabilities(
observables, probability_floor=0.04
)
print("uniform planning loss :", planning_loss(uniform, observables))
print("optimised planning loss:", optimisation.final_loss)
print("basis probabilities [X,Y,Z]:\n", optimisation.probabilities)

plan = sample_measurement_plan(
optimisation.probabilities, shots=4_000, seed=20260726
)
print("shots / unique backend jobs:", plan.shots, len(plan.grouped_shots))

runner = PyQPandaRunner(prepare, n_qubits=3)
dataset = run_measurement_plan(plan, runner, max_jobs=27)
estimates = estimate_observables(
dataset, observables, family_confidence=0.95
)
state = exact_statevector()
for observable in observables:
estimate = estimates[observable.name]
exact = observable.exact_expectation(state)
print(
f"{observable.name}: estimate={estimate.value:.5f}, "
f"exact={exact:.5f}, CI=[{estimate.lower:.5f}, {estimate.upper:.5f}], "
f"min_matches={estimate.minimum_term_matches}"
)

controller = ShadowBudgetController(
observables,
target_half_width=0.25,
family_confidence=0.95,
min_shots=1_000,
max_shots=8_000,
batch_shots=500,
)
report = controller.evaluate(dataset)
print(
"budget:",
report.reason,
"next_batch_shots=",
report.next_batch_shots,
"hard_max=",
report.max_shots,
)


if __name__ == "__main__":
main()
Loading