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
155 changes: 155 additions & 0 deletions pyqpanda-algorithm/pyqpanda_alg/VQE/VQE_README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
# VQE 模块 — 变分量子本征求解器

> Author: Bai

---

## 重要:请先安装缺失的依赖

项目 `requirements.txt` **未包含**所有运行时依赖,使用前请先执行:

```bash
# 系统库(pyqpanda3 的 C++ 后端需要 OpenMP 支持)
# sudo apt-get install -y libgomp1 # Ubuntu/Debian
# sudo yum install -y libgomp # Amazon Linux / RHEL

# requirements.txt 中遗漏但其他模块需要的 Python 包
pip install pandas scikit-learn
```

---

## 算法原理

### 目标

VQE 的目标是:**求一个哈密顿量 H 的最小本征值(基态能量)**。

最经典的应用场景:求解分子的基态能量。

数学表述:E0 = minθ<ψ(θ)|H|ψ(θ)>


其中:
- H是系统哈密顿量(一个 Hermitian 矩阵)
- ∣ψ(θ)⟩是参数化量子态(由量子线路产生)
- θ是待优化的经典参数

### 核心思想:变分原理

**变分原理**保证:对于任意试探态∣ψ⟩,其能量期望值一定 ≥ 基态能量:⟨ψ∣H∣ψ⟩≥E0

所以我们只需要不断调整θ,使得能量期望值越来越低,最终逼近E0

### 算法整体流程

```
┌─────────────────────────────────────────────────────────────┐
│ VQE 混合量子-经典循环 │
│ │
│ ┌──────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ 经典优化器 │────▶│ 参数化量子线路 │────▶│ 测量期望值 │
│ │ (更新 θ) │◀────│ (Ansatz) │ │ ⟨ψ(θ)|H|ψ(θ)⟩│ │
│ └──────────┘ └──────────────┘ └──────────────┘ │
│ ▲ │ │
│ │ 能量值 E(θ) │ │
│ └────────────────────────────────────────┘ │
│ │
│ 收敛条件: |E(θ_new) - E(θ_old)| < ε │
└─────────────────────────────────────────────────────────────┘
```

**四大核心组件:**

| 组件 | 作用 | 对应文件 |
|------|------|----------|
| 哈密顿量 | 将物理系统表示为 Pauli 算符的加权和 | hamiltonian.py |
| 参数化线路 | 生成试探量子态 | ansatz.py |
| 期望值测量 | 在量子硬件上计算 | measurement.py |
| 经典优化器 | 调整参数使能量最小 | vqe_solver.py |


### 参数化线路 (Ansatz)

本模块提供两种 Ansatz:

**Hardware Efficient Ansatz (HEA)**:通用、硬件友好
```
每层结构:RY旋转 → RZ旋转 → CNOT纠缠链
参数数量 = 量子比特数 × 2 × 层数
```

**RY-Linear Ansatz**:更简单,仅用 RY 门
```
每层结构:RY旋转 → CNOT纠缠链
参数数量 = 量子比特数 × 层数
```

## 环境要求

- Python 3.11 / 3.12 / 3.13
- pyqpanda3 >= 0.3.5
- numpy, scipy, matplotlib, sympy

### 哈密顿量功能测试(不依赖量子模拟器)

```bash
python3 -c "
from pyqpanda_alg.VQE import PauliHamiltonian
H = PauliHamiltonian()
H.add_term(-1.0523, 'II')
H.add_term(0.3979, 'IZ')
H.add_term(-0.3979, 'ZI')
H.add_term(-0.0112, 'ZZ')
H.add_term(0.1809, 'XX')
print(H)
print(f'量子比特数: {H.num_qubits}')
print(f'精确基态能量: {H.exact_ground_energy():.6f}')
"
```

期望输出:
```
-1.0523 * II +0.3979 * IZ -0.3979 * ZI -0.0112 * ZZ +0.1809 * XX
量子比特数: 2
精确基态能量: -1.857202
```

### 完整 VQE 求解测试(需要 pyqpanda3 量子模拟器)

```bash
python3 -c "
from pyqpanda_alg.VQE import VQESolver, PauliHamiltonian

H = PauliHamiltonian()
H.add_term(-1.0523, 'II')
H.add_term(0.3979, 'IZ')
H.add_term(-0.3979, 'ZI')
H.add_term(-0.0112, 'ZZ')
H.add_term(0.1809, 'XX')

solver = VQESolver(H, ansatz='hea', num_layers=2, optimizer='COBYLA', shots=4096)
print(solver)
result = solver.run()

print(f'VQE 能量: {result[\"energy\"]:.6f}')
print(f'精确能量: {H.exact_ground_energy():.6f}')
print(f'误差: {abs(result[\"energy\"] - H.exact_ground_energy()):.6f}')
print(f'迭代次数: {result[\"num_iterations\"]}')
print(f'是否收敛: {result[\"success\"]}')
"
```

期望输出:
```
VQESolver(qubits=2, ansatz='hea', layers=2, optimizer='COBYLA', shots=4096)
VQE 能量: -1.857202
精确能量: -1.857202
误差: 0.000000
迭代次数: 200
是否收敛: False
```

> 说明:`是否收敛: False` 表示 COBYLA 跑满了 200 次迭代上限后停止。实际能量已到达全局最优——优化器很早就找到了最优点,后续迭代是在微调已经足够好的参数。这是正常现象。

28 changes: 28 additions & 0 deletions pyqpanda-algorithm/pyqpanda_alg/VQE/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
'''
Variational Quantum Eigensolver (VQE) Module.

Provides tools for finding the ground state energy of a quantum system
using hybrid quantum-classical optimization.

Core components:
- VQESolver: main solver class
- PauliHamiltonian: Hamiltonian representation as sum of Pauli terms
- hardware_efficient_ansatz: commonly used parameterized circuit
- measure_expectation: Pauli expectation value measurement

Author: Bai
'''

from .hamiltonian import PauliHamiltonian
from .ansatz import hardware_efficient_ansatz, ry_linear_ansatz
from .measurement import measure_expectation, compute_energy
from .vqe_solver import VQESolver

__all__ = [
'VQESolver',
'PauliHamiltonian',
'hardware_efficient_ansatz',
'ry_linear_ansatz',
'measure_expectation',
'compute_energy',
]
135 changes: 135 additions & 0 deletions pyqpanda-algorithm/pyqpanda_alg/VQE/ansatz.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
"""
Parameterized quantum circuits (Ansatz) for VQE.
Author: Bai
"""

import numpy as np
from pyqpanda3.core import QCircuit, RY, RZ, CNOT, X


def hardware_efficient_ansatz(qubits, params, num_layers=2):
"""
Hardware Efficient Ansatz (HEA).

Structure per layer:
1. RY rotation on each qubit (parameterized)
2. RZ rotation on each qubit (parameterized)
3. Linear CNOT entanglement (qubit[i] -> qubit[i+1])

Total parameter count: num_qubits * 2 * num_layers

Parameters
qubits : list[int]
Qubit indices, e.g. [0, 1, 2, 3].
params : array_like
Parameter vector. Length = len(qubits) * 2 * num_layers.
num_layers : int, default=2
Number of repetition layers.

Returns
QCircuit : the constructed parameterized circuit.

Examples:
.. code-block:: python

import numpy as np
from pyqpanda_alg.VQE import hardware_efficient_ansatz

qubits = [0, 1, 2]
params = np.random.uniform(0, 2*np.pi, size=3*2*2)
circuit = hardware_efficient_ansatz(qubits, params, num_layers=2)
"""
n = len(qubits)
expected_params = n * 2 * num_layers
if len(params) != expected_params:
raise ValueError(
f"Expected {expected_params} parameters, got {len(params)}."
)

cir = QCircuit()
idx = 0

for _ in range(num_layers):
# RY rotation layer
for q in qubits:
cir << RY(q, params[idx])
idx += 1
# RZ rotation layer
for q in qubits:
cir << RZ(q, params[idx])
idx += 1
# Entanglement layer: linear CNOT chain
for i in range(n - 1):
cir << CNOT(qubits[i], qubits[i + 1])

return cir


def ry_linear_ansatz(qubits, params, num_layers=2):
"""
Simplified RY-only ansatz with linear entanglement.

A lighter alternative to HEA — uses only RY gates (no RZ).
Good for beginners and quick prototyping.

Total parameter count: num_qubits * num_layers

Parameters
qubits : list[int]
Qubit indices.
params : array_like
Parameter vector. Length = len(qubits) * num_layers.
num_layers : int, default=2
Number of repetition layers.

Returns
QCircuit : the constructed parameterized circuit.

Examples:
.. code-block:: python

import numpy as np
from pyqpanda_alg.VQE import ry_linear_ansatz

qubits = [0, 1]
params = np.random.uniform(0, 2*np.pi, size=2*2)
circuit = ry_linear_ansatz(qubits, params, num_layers=2)
"""
n = len(qubits)
expected_params = n * num_layers
if len(params) != expected_params:
raise ValueError(
f"Expected {expected_params} parameters, got {len(params)}."
)

cir = QCircuit()
idx = 0

for _ in range(num_layers):
for q in qubits:
cir << RY(q, params[idx])
idx += 1
for i in range(n - 1):
cir << CNOT(qubits[i], qubits[i + 1])

return cir


def param_count(num_qubits, num_layers, ansatz_type='hea'):
"""
Calculate total number of parameters for a given ansatz configuration.

Parameters
num_qubits : int
num_layers : int
ansatz_type : str, 'hea' or 'ry_linear'

Returns
int : total parameter count
"""
if ansatz_type == 'hea':
return num_qubits * 2 * num_layers
elif ansatz_type == 'ry_linear':
return num_qubits * num_layers
else:
raise ValueError(f"Unknown ansatz type: {ansatz_type}")
Loading