VQE实现示例
In [1]:
Copied!
import numpy as np
from qibo import Circuit, gates, hamiltonians
from qibo.hamiltonians import XXZ
from qibo.models import VQE
nqubits = 6
nlayers = 4
import numpy as np
from qibo import Circuit, gates, hamiltonians
from qibo.hamiltonians import XXZ
from qibo.models import VQE
nqubits = 6
nlayers = 4
In [2]:
Copied!
import qibo
qibo.set_backend("qibojit")
import qibo
qibo.set_backend("qibojit")
[Qibo 0.2.20|INFO|2025-09-09 09:43:55]: Using qibojit (numba) backend on /CPU:0
In [3]:
Copied!
# Create variational circuit
circuit = Circuit(nqubits)
for l in range(nlayers):
circuit.add(gates.RY(qubit, theta=0.0) for qubit in range(nqubits))
circuit.add(gates.CZ(qubit, qubit + 1) for qubit in range(0, nqubits - 1, 2))
circuit.add(gates.RY(qubit, theta=0.0) for qubit in range(nqubits))
circuit.add(gates.CZ(qubit, qubit + 1) for qubit in range(1, nqubits - 2, 2))
circuit.add(gates.CZ(0, nqubits - 1))
circuit.add(gates.RY(qubit, theta=0.0) for qubit in range(nqubits))
circuit.draw()
# Create variational circuit
circuit = Circuit(nqubits)
for l in range(nlayers):
circuit.add(gates.RY(qubit, theta=0.0) for qubit in range(nqubits))
circuit.add(gates.CZ(qubit, qubit + 1) for qubit in range(0, nqubits - 1, 2))
circuit.add(gates.RY(qubit, theta=0.0) for qubit in range(nqubits))
circuit.add(gates.CZ(qubit, qubit + 1) for qubit in range(1, nqubits - 2, 2))
circuit.add(gates.CZ(0, nqubits - 1))
circuit.add(gates.RY(qubit, theta=0.0) for qubit in range(nqubits))
circuit.draw()
0: ─RY─o─────RY─────o─RY─o─────RY─────o─RY─o─────RY─────o─RY─o─────RY──── ... 1: ─RY─Z─────RY─o───|─RY─Z─────RY─o───|─RY─Z─────RY─o───|─RY─Z─────RY─o── ... 2: ─RY───o───RY─Z───|─RY───o───RY─Z───|─RY───o───RY─Z───|─RY───o───RY─Z── ... 3: ─RY───Z───RY───o─|─RY───Z───RY───o─|─RY───Z───RY───o─|─RY───Z───RY───o ... 4: ─RY─────o─RY───Z─|─RY─────o─RY───Z─|─RY─────o─RY───Z─|─RY─────o─RY───Z ... 5: ─RY─────Z─RY─────Z─RY─────Z─RY─────Z─RY─────Z─RY─────Z─RY─────Z─RY──── ... 0: ... ─o─RY─ 1: ... ─|─RY─ 2: ... ─|─RY─ 3: ... ─|─RY─ 4: ... ─|─RY─ 5: ... ─Z─RY─
In [41]:
Copied!
initial_parameters = np.random.uniform(0, 2 * np.pi, nqubits * (2 * nlayers + 1))
print(initial_parameters)
initial_parameters = np.random.uniform(0, 2 * np.pi, nqubits * (2 * nlayers + 1))
print(initial_parameters)
[4.92805959 5.44855108 4.11417461 4.86444869 1.05833279 2.93897212 1.52895934 4.62844094 4.19999981 1.81721197 5.64114505 5.52781326 3.27966832 5.41597617 3.60011232 4.42855116 1.01101978 4.70786628 0.40512803 4.60923502 1.34705171 1.251013 4.77379592 1.23383625 0.47570349 0.0743672 4.87205339 3.50849381 5.71411356 4.25557447 3.494453 5.61112733 5.63730198 2.59171654 4.26771344 1.80438955 2.17202354 1.76598538 2.33152001 4.6729965 1.22467215 3.15323815 1.22350846 4.8346671 4.7331064 1.06570593 4.45137383 4.09645096 5.73812121 4.4802333 4.23518094 3.11807078 0.55528338 5.51121961]
In [42]:
Copied!
circuit.set_parameters(initial_parameters)
state = circuit()
circuit.set_parameters(initial_parameters)
state = circuit()
In [44]:
Copied!
state.state()
state.state()
Out[44]:
array([ 0.09197655+0.j, 0.0921345 +0.j, 0.10114786+0.j, 0.14924903+0.j,
-0.09145835+0.j, -0.1903287 +0.j, 0.1056831 +0.j, -0.01394478+0.j,
-0.01692741+0.j, 0.06989537+0.j, 0.01844129-0.j, -0.00999345+0.j,
0.07014703+0.j, 0.03877442+0.j, 0.0035795 +0.j, 0.17428058+0.j,
-0.2234318 +0.j, -0.03693061+0.j, -0.06743177+0.j, -0.01792737+0.j,
0.09828714+0.j, -0.01770805+0.j, 0.08826791-0.j, -0.11702182+0.j,
-0.0417063 +0.j, -0.09199374+0.j, -0.10463418+0.j, -0.01753629+0.j,
0.06862338-0.j, -0.02845973+0.j, 0.040514 -0.j, -0.05445149+0.j,
-0.03358641+0.j, 0.25590912+0.j, 0.09303949-0.j, -0.20023644+0.j,
0.21998123-0.j, -0.11649291+0.j, -0.06295437-0.j, -0.17388287+0.j,
-0.01967436+0.j, 0.16591477+0.j, -0.00742568+0.j, 0.098501 +0.j,
-0.09883791+0.j, 0.10119023+0.j, -0.07295278+0.j, 0.01874692+0.j,
-0.0319076 +0.j, -0.06914431+0.j, 0.24031839+0.j, -0.03004489+0.j,
0.21748951-0.j, -0.1352233 +0.j, 0.14383803+0.j, 0.00603818+0.j,
-0.1313958 +0.j, 0.01468867+0.j, -0.43656139+0.j, 0.14402356+0.j,
0.20038101+0.j, -0.04417291+0.j, 0.18860432+0.j, 0.02893417+0.j])
$$ \hat{H}_{\text{XXZ}} = \frac{J}{4} \sum_{i=1}^{N} \left[ \hat{X}_{i} \hat{X}_{i+1} + \hat{Y}_{i} \hat{Y}_{i+1} + \Delta \hat{Z}_{i} \hat{Z}_{i+1} \right] $$
In [45]:
Copied!
from scipy.sparse import kron, eye, diags
from scipy.sparse import csr_matrix
def create_xxz_hamiltonian(N, J=1, Delta=0.5):
"""
创建XXZ哈密顿量的矩阵表示
参数:
N (int): 量子比特数量
J (float): 耦合强度,默认为1
Delta (float): 各向异性参数,默认为0.5
返回:
numpy.ndarray: 2^N × 2^N的哈密顿量矩阵
"""
# 定义Pauli矩阵
X = np.array([[0, 1], [1, 0]], dtype=complex)
Y = np.array([[0, -1j], [1j, 0]], dtype=complex)
Z = np.array([[1, 0], [0, -1]], dtype=complex)
I = np.eye(2, dtype=complex)
# 初始化哈密顿量为零矩阵
H = np.zeros((2**N, 2**N), dtype=complex)
# 构建周期性边界条件的哈密顿量
for i in range(N):
# 确定下一个量子比特的索引(考虑周期性边界条件)
next_i = (i + 1) % N
# 构建作用于第i和i+1个量子比特的算符
# 对于不作用的量子比特,使用单位矩阵
# XX项
XX_op = 1
for j in range(N):
if j == i or j == next_i:
XX_op = np.kron(XX_op, X)
else:
XX_op = np.kron(XX_op, I)
# YY项
YY_op = 1
for j in range(N):
if j == i or j == next_i:
YY_op = np.kron(YY_op, Y)
else:
YY_op = np.kron(YY_op, I)
# ZZ项
ZZ_op = 1
for j in range(N):
if j == i or j == next_i:
ZZ_op = np.kron(ZZ_op, Z)
else:
ZZ_op = np.kron(ZZ_op, I)
# 将当前项添加到哈密顿量
H += (J/4) * (XX_op + YY_op + Delta * ZZ_op)
return H
from scipy.sparse import kron, eye, diags
from scipy.sparse import csr_matrix
def create_xxz_hamiltonian(N, J=1, Delta=0.5):
"""
创建XXZ哈密顿量的矩阵表示
参数:
N (int): 量子比特数量
J (float): 耦合强度,默认为1
Delta (float): 各向异性参数,默认为0.5
返回:
numpy.ndarray: 2^N × 2^N的哈密顿量矩阵
"""
# 定义Pauli矩阵
X = np.array([[0, 1], [1, 0]], dtype=complex)
Y = np.array([[0, -1j], [1j, 0]], dtype=complex)
Z = np.array([[1, 0], [0, -1]], dtype=complex)
I = np.eye(2, dtype=complex)
# 初始化哈密顿量为零矩阵
H = np.zeros((2**N, 2**N), dtype=complex)
# 构建周期性边界条件的哈密顿量
for i in range(N):
# 确定下一个量子比特的索引(考虑周期性边界条件)
next_i = (i + 1) % N
# 构建作用于第i和i+1个量子比特的算符
# 对于不作用的量子比特,使用单位矩阵
# XX项
XX_op = 1
for j in range(N):
if j == i or j == next_i:
XX_op = np.kron(XX_op, X)
else:
XX_op = np.kron(XX_op, I)
# YY项
YY_op = 1
for j in range(N):
if j == i or j == next_i:
YY_op = np.kron(YY_op, Y)
else:
YY_op = np.kron(YY_op, I)
# ZZ项
ZZ_op = 1
for j in range(N):
if j == i or j == next_i:
ZZ_op = np.kron(ZZ_op, Z)
else:
ZZ_op = np.kron(ZZ_op, I)
# 将当前项添加到哈密顿量
H += (J/4) * (XX_op + YY_op + Delta * ZZ_op)
return H
In [61]:
Copied!
create_xxz_hamiltonian(6,4,0.5)
create_xxz_hamiltonian(6,4,0.5)
Out[61]:
array([[3.+0.j, 0.+0.j, 0.+0.j, ..., 0.+0.j, 0.+0.j, 0.+0.j],
[0.+0.j, 1.+0.j, 2.+0.j, ..., 0.+0.j, 0.+0.j, 0.+0.j],
[0.+0.j, 2.+0.j, 1.+0.j, ..., 0.+0.j, 0.+0.j, 0.+0.j],
...,
[0.+0.j, 0.+0.j, 0.+0.j, ..., 1.+0.j, 2.+0.j, 0.+0.j],
[0.+0.j, 0.+0.j, 0.+0.j, ..., 2.+0.j, 1.+0.j, 0.+0.j],
[0.+0.j, 0.+0.j, 0.+0.j, ..., 0.+0.j, 0.+0.j, 3.+0.j]],
shape=(64, 64))
In [49]:
Copied!
import numpy as np
from scipy.sparse import kron, eye, diags
from scipy.sparse import csr_matrix
def create_xxz_hamiltonian_sparse(N, J=1, Delta=0.5):
"""
创建XXZ哈密顿量的稀疏矩阵表示
参数:
N (int): 量子比特数量
J (float): 耦合强度,默认为1
Delta (float): 各向异性参数,默认为0.5
返回:
scipy.sparse.csr_matrix: 2^N × 2^N的稀疏哈密顿量矩阵
"""
# 定义Pauli矩阵(稀疏形式)
X = csr_matrix([[0, 1], [1, 0]], dtype=complex)
Y = csr_matrix([[0, -1j], [1j, 0]], dtype=complex)
Z = csr_matrix([[1, 0], [0, -1]], dtype=complex)
I = eye(2, dtype=complex, format='csr')
# 初始化哈密顿量为零矩阵
H = csr_matrix((2**N, 2**N), dtype=complex)
# 构建周期性边界条件的哈密顿量
for i in range(N):
# 确定下一个量子比特的索引(考虑周期性边界条件)
next_i = (i + 1) % N
# 构建作用于第i和i+1个量子比特的算符
# 对于不作用的量子比特,使用单位矩阵
# XX项
XX_op = None
for j in range(N):
if j == i or j == next_i:
if XX_op is None:
XX_op = X
else:
XX_op = kron(XX_op, X)
else:
if XX_op is None:
XX_op = I
else:
XX_op = kron(XX_op, I)
# YY项
YY_op = None
for j in range(N):
if j == i or j == next_i:
if YY_op is None:
YY_op = Y
else:
YY_op = kron(YY_op, Y)
else:
if YY_op is None:
YY_op = I
else:
YY_op = kron(YY_op, I)
# ZZ项
ZZ_op = None
for j in range(N):
if j == i or j == next_i:
if ZZ_op is None:
ZZ_op = Z
else:
ZZ_op = kron(ZZ_op, Z)
else:
if ZZ_op is None:
ZZ_op = I
else:
ZZ_op = kron(ZZ_op, I)
# 将当前项添加到哈密顿量
H += (J/4) * (XX_op + YY_op + Delta * ZZ_op)
return H
import numpy as np
from scipy.sparse import kron, eye, diags
from scipy.sparse import csr_matrix
def create_xxz_hamiltonian_sparse(N, J=1, Delta=0.5):
"""
创建XXZ哈密顿量的稀疏矩阵表示
参数:
N (int): 量子比特数量
J (float): 耦合强度,默认为1
Delta (float): 各向异性参数,默认为0.5
返回:
scipy.sparse.csr_matrix: 2^N × 2^N的稀疏哈密顿量矩阵
"""
# 定义Pauli矩阵(稀疏形式)
X = csr_matrix([[0, 1], [1, 0]], dtype=complex)
Y = csr_matrix([[0, -1j], [1j, 0]], dtype=complex)
Z = csr_matrix([[1, 0], [0, -1]], dtype=complex)
I = eye(2, dtype=complex, format='csr')
# 初始化哈密顿量为零矩阵
H = csr_matrix((2**N, 2**N), dtype=complex)
# 构建周期性边界条件的哈密顿量
for i in range(N):
# 确定下一个量子比特的索引(考虑周期性边界条件)
next_i = (i + 1) % N
# 构建作用于第i和i+1个量子比特的算符
# 对于不作用的量子比特,使用单位矩阵
# XX项
XX_op = None
for j in range(N):
if j == i or j == next_i:
if XX_op is None:
XX_op = X
else:
XX_op = kron(XX_op, X)
else:
if XX_op is None:
XX_op = I
else:
XX_op = kron(XX_op, I)
# YY项
YY_op = None
for j in range(N):
if j == i or j == next_i:
if YY_op is None:
YY_op = Y
else:
YY_op = kron(YY_op, Y)
else:
if YY_op is None:
YY_op = I
else:
YY_op = kron(YY_op, I)
# ZZ项
ZZ_op = None
for j in range(N):
if j == i or j == next_i:
if ZZ_op is None:
ZZ_op = Z
else:
ZZ_op = kron(ZZ_op, Z)
else:
if ZZ_op is None:
ZZ_op = I
else:
ZZ_op = kron(ZZ_op, I)
# 将当前项添加到哈密顿量
H += (J/4) * (XX_op + YY_op + Delta * ZZ_op)
return H
In [53]:
Copied!
def calculate_expectation(state_vector, hamiltonian_sparse):
"""
计算给定状态在哈密顿量下的期望值
参数:
state_vector: 量子态向量
hamiltonian_sparse: 稀疏哈密顿量矩阵
返回:
期望值
"""
# 计算 H|ψ⟩
H_psi = hamiltonian_sparse @ state_vector
# 计算 ⟨ψ|H|ψ⟩
expectation = np.vdot(state_vector, H_psi)
# 返回实部(因为期望值应该是实数)
return expectation.real
def calculate_expectation(state_vector, hamiltonian_sparse):
"""
计算给定状态在哈密顿量下的期望值
参数:
state_vector: 量子态向量
hamiltonian_sparse: 稀疏哈密顿量矩阵
返回:
期望值
"""
# 计算 H|ψ⟩
H_psi = hamiltonian_sparse @ state_vector
# 计算 ⟨ψ|H|ψ⟩
expectation = np.vdot(state_vector, H_psi)
# 返回实部(因为期望值应该是实数)
return expectation.real
期望值: -0.38356459231746065
In [62]:
Copied!
H_sparse = create_xxz_hamiltonian_sparse(N=nqubits, J=4, Delta=0.5)
H_sparse = create_xxz_hamiltonian_sparse(N=nqubits, J=4, Delta=0.5)
In [63]:
Copied!
def expectation_value(params):
circuit.set_parameters(params)
state = circuit()
state_vector = state.state()
expectation = calculate_expectation(state_vector, H_sparse)
return expectation
def expectation_value(params):
circuit.set_parameters(params)
state = circuit()
state_vector = state.state()
expectation = calculate_expectation(state_vector, H_sparse)
return expectation
In [73]:
Copied!
from scipy.optimize import minimize
# 定义优化目标函数(最小化期望值)
def objective_function(params):
return expectation_value(params)
#hamiltonian = XXZ(nqubits=nqubits)
#vqe = VQE(circuit, hamiltonian)
# 初始参数
initial_parameters = np.random.uniform(0, 2 * np.pi, nqubits * (2 * nlayers + 1))
#best, params, extra = vqe.minimize(initial_parameters, method='BFGS', compile=False)
# 使用BFGS方法进行优化
from scipy.optimize import minimize
# 定义优化目标函数(最小化期望值)
def objective_function(params):
return expectation_value(params)
#hamiltonian = XXZ(nqubits=nqubits)
#vqe = VQE(circuit, hamiltonian)
# 初始参数
initial_parameters = np.random.uniform(0, 2 * np.pi, nqubits * (2 * nlayers + 1))
#best, params, extra = vqe.minimize(initial_parameters, method='BFGS', compile=False)
# 使用BFGS方法进行优化
In [74]:
Copied!
initial_parameters = np.random.uniform(0, 2 * np.pi, nqubits * (2 * nlayers + 1))
result = minimize(objective_function,
initial_parameters,
method='BFGS',
options={'disp': True, 'maxiter': 1000})
# 获取优化结果
optimized_params = result.x
min_expectation = result.fun
optimization_info = result
print(f"自定义BFGS方法得到的最小期望值: {min_expectation}")
state = circuit().state()
print(f"VQE得到的量子态向量: {state}")
initial_parameters = np.random.uniform(0, 2 * np.pi, nqubits * (2 * nlayers + 1))
result = minimize(objective_function,
initial_parameters,
method='BFGS',
options={'disp': True, 'maxiter': 1000})
# 获取优化结果
optimized_params = result.x
min_expectation = result.fun
optimization_info = result
print(f"自定义BFGS方法得到的最小期望值: {min_expectation}")
state = circuit().state()
print(f"VQE得到的量子态向量: {state}")
Optimization terminated successfully.
Current function value: -9.453101
Iterations: 151
Function evaluations: 8580
Gradient evaluations: 156
自定义BFGS方法得到的最小期望值: -9.453101221467115
VQE得到的量子态向量: [-3.88131645e-03+0.j 4.34714462e-03+0.j -6.68877364e-04+0.j
5.02364987e-03+0.j -6.58155842e-03+0.j 2.75888085e-03+0.j
-1.99492704e-03+0.j -9.46967042e-02+0.j -1.51525574e-03+0.j
-5.73316919e-04+0.j 2.80598695e-03+0.j 2.27959722e-01+0.j
-1.55688715e-02+0.j -2.24606649e-01+0.j 8.99531521e-02+0.j
-4.80577184e-03+0.j 2.48063868e-03+0.j 6.97576025e-03+0.j
-9.03612929e-03+0.j -2.19391169e-01+0.j 8.95275053e-04+0.j
4.12304757e-01+0.j -2.31490419e-01+0.j -1.35950097e-03+0.j
-1.84191899e-03+0.j -2.18572995e-01+0.j 2.35127671e-01+0.j
-1.38458404e-04+0.j -8.83353886e-02+0.j -2.77309656e-07+0.j
2.30605232e-03+0.j -3.95319244e-03+0.j 3.09262041e-03+0.j
7.16907581e-03+0.j 7.29858038e-03+0.j 8.96840193e-02+0.j
-6.23044733e-03+0.j -2.20974742e-01+0.j 2.10708862e-01+0.j
4.19086091e-03+0.j 6.51253241e-03+0.j 2.27232464e-01+0.j
-4.19346298e-01+0.j 2.99001185e-04+0.j 2.28900714e-01+0.j
2.42388754e-03+0.j 1.08142184e-03+0.j -2.29214726e-03+0.j
1.17399730e-02+0.j -8.65192925e-02+0.j 2.20201163e-01+0.j
7.61070360e-03+0.j -2.29165443e-01+0.j 4.52470753e-04+0.j
-4.06480816e-03+0.j -2.55990604e-03+0.j 8.37691109e-02+0.j
1.38821379e-02+0.j 4.03889634e-03+0.j -3.50081216e-03+0.j
-3.85956186e-03+0.j -2.69231979e-04+0.j 6.97874328e-03+0.j
-2.23832214e-03+0.j]
In [78]:
Copied!
# 设置循环次数
num_runs = 5 # 你可以根据需要调整这个值
# 创建列表来存储每次运行的结果
expectations = []
parameters = []
states = []
for i in range(num_runs):
print(f"\n=== 运行 {i+1}/{num_runs} ===")
# 生成随机初始化参数
initial_parameters = np.random.uniform(0, 2 * np.pi, nqubits * (2 * nlayers + 1))
# 执行优化
result = minimize(objective_function,
initial_parameters,
method='BFGS',
options={'disp': True, 'maxiter': 1000})
# 获取优化结果
optimized_params = result.x
min_expectation = result.fun
# 获取最终量子态
circuit.set_parameters(optimized_params)
state = circuit().state()
# 存储结果
expectations.append(min_expectation)
parameters.append(optimized_params)
states.append(state)
# 打印当前运行结果
print(f"运行 {i+1} 得到的最小期望值: {min_expectation}")
# 设置循环次数
num_runs = 5 # 你可以根据需要调整这个值
# 创建列表来存储每次运行的结果
expectations = []
parameters = []
states = []
for i in range(num_runs):
print(f"\n=== 运行 {i+1}/{num_runs} ===")
# 生成随机初始化参数
initial_parameters = np.random.uniform(0, 2 * np.pi, nqubits * (2 * nlayers + 1))
# 执行优化
result = minimize(objective_function,
initial_parameters,
method='BFGS',
options={'disp': True, 'maxiter': 1000})
# 获取优化结果
optimized_params = result.x
min_expectation = result.fun
# 获取最终量子态
circuit.set_parameters(optimized_params)
state = circuit().state()
# 存储结果
expectations.append(min_expectation)
parameters.append(optimized_params)
states.append(state)
# 打印当前运行结果
print(f"运行 {i+1} 得到的最小期望值: {min_expectation}")
=== 运行 1/5 ===
Optimization terminated successfully.
Current function value: -9.470129
Iterations: 232
Function evaluations: 13255
Gradient evaluations: 241
运行 1 得到的最小期望值: -9.470128866570583
=== 运行 2/5 ===
Optimization terminated successfully.
Current function value: -9.467449
Iterations: 284
Function evaluations: 16060
Gradient evaluations: 292
运行 2 得到的最小期望值: -9.467449031705627
=== 运行 3/5 ===
Optimization terminated successfully.
Current function value: -9.468723
Iterations: 251
Function evaluations: 14520
Gradient evaluations: 264
运行 3 得到的最小期望值: -9.468723307073681
=== 运行 4/5 ===
Optimization terminated successfully.
Current function value: -9.472136
Iterations: 103
Function evaluations: 5830
Gradient evaluations: 106
运行 4 得到的最小期望值: -9.472135954892252
=== 运行 5/5 ===
Optimization terminated successfully.
Current function value: -9.471137
Iterations: 344
Function evaluations: 19580
Gradient evaluations: 356
运行 5 得到的最小期望值: -9.471137452357675
=== 结果分析 ===
所有运行的最小期望值: [np.float64(-9.470128866570583), np.float64(-9.467449031705627), np.float64(-9.468723307073681), np.float64(-9.472135954892252), np.float64(-9.471137452357675)]
最小期望值的最小值: -9.472135954892252
最小期望值的最大值: -9.467449031705627
最小期望值的平均值: -9.469914922519964
最小期望值的标准差: 0.0016717596082986925
e:\quantum computing\venv\Lib\site-packages\IPython\core\pylabtools.py:170: UserWarning: Glyph 26368 (\N{CJK UNIFIED IDEOGRAPH-6700}) missing from font(s) DejaVu Sans.
fig.canvas.print_figure(bytes_io, **kw)
e:\quantum computing\venv\Lib\site-packages\IPython\core\pylabtools.py:170: UserWarning: Glyph 23567 (\N{CJK UNIFIED IDEOGRAPH-5C0F}) missing from font(s) DejaVu Sans.
fig.canvas.print_figure(bytes_io, **kw)
e:\quantum computing\venv\Lib\site-packages\IPython\core\pylabtools.py:170: UserWarning: Glyph 26399 (\N{CJK UNIFIED IDEOGRAPH-671F}) missing from font(s) DejaVu Sans.
fig.canvas.print_figure(bytes_io, **kw)
e:\quantum computing\venv\Lib\site-packages\IPython\core\pylabtools.py:170: UserWarning: Glyph 26395 (\N{CJK UNIFIED IDEOGRAPH-671B}) missing from font(s) DejaVu Sans.
fig.canvas.print_figure(bytes_io, **kw)
e:\quantum computing\venv\Lib\site-packages\IPython\core\pylabtools.py:170: UserWarning: Glyph 20540 (\N{CJK UNIFIED IDEOGRAPH-503C}) missing from font(s) DejaVu Sans.
fig.canvas.print_figure(bytes_io, **kw)
e:\quantum computing\venv\Lib\site-packages\IPython\core\pylabtools.py:170: UserWarning: Glyph 19981 (\N{CJK UNIFIED IDEOGRAPH-4E0D}) missing from font(s) DejaVu Sans.
fig.canvas.print_figure(bytes_io, **kw)
e:\quantum computing\venv\Lib\site-packages\IPython\core\pylabtools.py:170: UserWarning: Glyph 21516 (\N{CJK UNIFIED IDEOGRAPH-540C}) missing from font(s) DejaVu Sans.
fig.canvas.print_figure(bytes_io, **kw)
e:\quantum computing\venv\Lib\site-packages\IPython\core\pylabtools.py:170: UserWarning: Glyph 21021 (\N{CJK UNIFIED IDEOGRAPH-521D}) missing from font(s) DejaVu Sans.
fig.canvas.print_figure(bytes_io, **kw)
e:\quantum computing\venv\Lib\site-packages\IPython\core\pylabtools.py:170: UserWarning: Glyph 22987 (\N{CJK UNIFIED IDEOGRAPH-59CB}) missing from font(s) DejaVu Sans.
fig.canvas.print_figure(bytes_io, **kw)
e:\quantum computing\venv\Lib\site-packages\IPython\core\pylabtools.py:170: UserWarning: Glyph 21270 (\N{CJK UNIFIED IDEOGRAPH-5316}) missing from font(s) DejaVu Sans.
fig.canvas.print_figure(bytes_io, **kw)
e:\quantum computing\venv\Lib\site-packages\IPython\core\pylabtools.py:170: UserWarning: Glyph 21442 (\N{CJK UNIFIED IDEOGRAPH-53C2}) missing from font(s) DejaVu Sans.
fig.canvas.print_figure(bytes_io, **kw)
e:\quantum computing\venv\Lib\site-packages\IPython\core\pylabtools.py:170: UserWarning: Glyph 25968 (\N{CJK UNIFIED IDEOGRAPH-6570}) missing from font(s) DejaVu Sans.
fig.canvas.print_figure(bytes_io, **kw)
e:\quantum computing\venv\Lib\site-packages\IPython\core\pylabtools.py:170: UserWarning: Glyph 19979 (\N{CJK UNIFIED IDEOGRAPH-4E0B}) missing from font(s) DejaVu Sans.
fig.canvas.print_figure(bytes_io, **kw)
e:\quantum computing\venv\Lib\site-packages\IPython\core\pylabtools.py:170: UserWarning: Glyph 30340 (\N{CJK UNIFIED IDEOGRAPH-7684}) missing from font(s) DejaVu Sans.
fig.canvas.print_figure(bytes_io, **kw)
e:\quantum computing\venv\Lib\site-packages\IPython\core\pylabtools.py:170: UserWarning: Glyph 36816 (\N{CJK UNIFIED IDEOGRAPH-8FD0}) missing from font(s) DejaVu Sans.
fig.canvas.print_figure(bytes_io, **kw)
e:\quantum computing\venv\Lib\site-packages\IPython\core\pylabtools.py:170: UserWarning: Glyph 34892 (\N{CJK UNIFIED IDEOGRAPH-884C}) missing from font(s) DejaVu Sans.
fig.canvas.print_figure(bytes_io, **kw)
e:\quantum computing\venv\Lib\site-packages\IPython\core\pylabtools.py:170: UserWarning: Glyph 27425 (\N{CJK UNIFIED IDEOGRAPH-6B21}) missing from font(s) DejaVu Sans.
fig.canvas.print_figure(bytes_io, **kw)
e:\quantum computing\venv\Lib\site-packages\IPython\core\pylabtools.py:170: UserWarning: Glyph 25391 (\N{CJK UNIFIED IDEOGRAPH-632F}) missing from font(s) DejaVu Sans.
fig.canvas.print_figure(bytes_io, **kw)
e:\quantum computing\venv\Lib\site-packages\IPython\core\pylabtools.py:170: UserWarning: Glyph 24133 (\N{CJK UNIFIED IDEOGRAPH-5E45}) missing from font(s) DejaVu Sans.
fig.canvas.print_figure(bytes_io, **kw)
e:\quantum computing\venv\Lib\site-packages\IPython\core\pylabtools.py:170: UserWarning: Glyph 37327 (\N{CJK UNIFIED IDEOGRAPH-91CF}) missing from font(s) DejaVu Sans.
fig.canvas.print_figure(bytes_io, **kw)
e:\quantum computing\venv\Lib\site-packages\IPython\core\pylabtools.py:170: UserWarning: Glyph 23376 (\N{CJK UNIFIED IDEOGRAPH-5B50}) missing from font(s) DejaVu Sans.
fig.canvas.print_figure(bytes_io, **kw)
e:\quantum computing\venv\Lib\site-packages\IPython\core\pylabtools.py:170: UserWarning: Glyph 24577 (\N{CJK UNIFIED IDEOGRAPH-6001}) missing from font(s) DejaVu Sans.
fig.canvas.print_figure(bytes_io, **kw)
e:\quantum computing\venv\Lib\site-packages\IPython\core\pylabtools.py:170: UserWarning: Glyph 32034 (\N{CJK UNIFIED IDEOGRAPH-7D22}) missing from font(s) DejaVu Sans.
fig.canvas.print_figure(bytes_io, **kw)
e:\quantum computing\venv\Lib\site-packages\IPython\core\pylabtools.py:170: UserWarning: Glyph 24341 (\N{CJK UNIFIED IDEOGRAPH-5F15}) missing from font(s) DejaVu Sans.
fig.canvas.print_figure(bytes_io, **kw)
In [82]:
Copied!
# 分析结果
print("\n=== 结果分析 ===")
print(f"所有运行的最小期望值: {expectations}")
print(f"最小期望值的最小值: {min(expectations)}")
print(f"最小期望值的最大值: {max(expectations)}")
print(f"最小期望值的平均值: {np.mean(expectations)}")
print(f"最小期望值的标准差: {np.std(expectations)}")
# 绘制不同运行得到的期望值
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 6))
plt.plot(range(1, num_runs+1), expectations, 'bo-')
plt.title('minimum expectation values over different initial parameters')
plt.xlabel('run number')
plt.ylabel('minimum expectation value')
plt.grid(True)
plt.show()
# 绘制不同运行得到的量子态对比
plt.figure(figsize=(12, 8))
# 定义不同的线型和颜色组合
line_styles = ['-', '--', '-.', ':']
colors = ['b', 'g', 'r', 'c', 'm', 'y', 'k']
for i, state in enumerate(states):
# 循环使用线型和颜色
line_style = line_styles[i % len(line_styles)]
color = colors[i % len(colors)]
plt.plot(np.abs(state),
linestyle=line_style,
color=color,
label=f'run {i+1}')
plt.title('amplitudes of the minimum state over different initial parameters')
plt.xlabel('state index')
plt.ylabel('amplitude')
plt.legend()
plt.grid(True)
plt.show()
# 分析结果
print("\n=== 结果分析 ===")
print(f"所有运行的最小期望值: {expectations}")
print(f"最小期望值的最小值: {min(expectations)}")
print(f"最小期望值的最大值: {max(expectations)}")
print(f"最小期望值的平均值: {np.mean(expectations)}")
print(f"最小期望值的标准差: {np.std(expectations)}")
# 绘制不同运行得到的期望值
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 6))
plt.plot(range(1, num_runs+1), expectations, 'bo-')
plt.title('minimum expectation values over different initial parameters')
plt.xlabel('run number')
plt.ylabel('minimum expectation value')
plt.grid(True)
plt.show()
# 绘制不同运行得到的量子态对比
plt.figure(figsize=(12, 8))
# 定义不同的线型和颜色组合
line_styles = ['-', '--', '-.', ':']
colors = ['b', 'g', 'r', 'c', 'm', 'y', 'k']
for i, state in enumerate(states):
# 循环使用线型和颜色
line_style = line_styles[i % len(line_styles)]
color = colors[i % len(colors)]
plt.plot(np.abs(state),
linestyle=line_style,
color=color,
label=f'run {i+1}')
plt.title('amplitudes of the minimum state over different initial parameters')
plt.xlabel('state index')
plt.ylabel('amplitude')
plt.legend()
plt.grid(True)
plt.show()
=== 结果分析 === 所有运行的最小期望值: [np.float64(-9.470128866570583), np.float64(-9.467449031705627), np.float64(-9.468723307073681), np.float64(-9.472135954892252), np.float64(-9.471137452357675)] 最小期望值的最小值: -9.472135954892252 最小期望值的最大值: -9.467449031705627 最小期望值的平均值: -9.469914922519964 最小期望值的标准差: 0.0016717596082986925
In [77]:
Copied!
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 6))
plt.plot(state, 'b-', linewidth=1)
plt.title('Quantum State Vector')
plt.xlabel('State Index')
plt.ylabel('Amplitude')
plt.grid(True)
plt.show()
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 6))
plt.plot(state, 'b-', linewidth=1)
plt.title('Quantum State Vector')
plt.xlabel('State Index')
plt.ylabel('Amplitude')
plt.grid(True)
plt.show()
e:\quantum computing\venv\Lib\site-packages\matplotlib\cbook.py:1719: ComplexWarning: Casting complex values to real discards the imaginary part return math.isfinite(val) e:\quantum computing\venv\Lib\site-packages\matplotlib\cbook.py:1355: ComplexWarning: Casting complex values to real discards the imaginary part return np.asarray(x, float)
In [69]:
Copied!
hamiltonian = XXZ(nqubits=nqubits)
vqe = VQE(circuit, hamiltonian)
best, params, extra = vqe.minimize(initial_parameters, method='BFGS', compile=False)
print(f"Qibo内置VQE得到的最小期望值: {best}")
hamiltonian = XXZ(nqubits=nqubits)
vqe = VQE(circuit, hamiltonian)
best, params, extra = vqe.minimize(initial_parameters, method='BFGS', compile=False)
print(f"Qibo内置VQE得到的最小期望值: {best}")
Qibo内置VQE得到的最小期望值: -9.47213586830712
In [71]:
Copied!
state = circuit().state()
print(f"Qibo内置VQE得到的量子态向量: {state}")
state = circuit().state()
print(f"Qibo内置VQE得到的量子态向量: {state}")
Qibo内置VQE得到的量子态向量: [-1.35713044e-07+0.j 1.61994088e-05-0.j 1.35501737e-05+0.j 2.42544182e-07+0.j 4.68297124e-06+0.j 2.92052641e-08+0.j 2.26212011e-07+0.j -8.59274694e-02+0.j 4.07288925e-06+0.j -9.49886835e-07+0.j 3.59413871e-07+0.j 2.25024168e-01-0.j 1.69795169e-07+0.j -2.25032579e-01+0.j 8.59243998e-02+0.j -2.03663045e-07+0.j -8.55160394e-06+0.j 3.82796617e-07+0.j -5.86138071e-07+0.j -2.25002303e-01+0.j 1.77170053e-07+0.j 4.17186753e-01-0.j -2.25024561e-01+0.j -2.89866328e-07+0.j 3.91081625e-07+0.j -2.25017600e-01+0.j 2.25019218e-01+0.j 1.96830951e-07+0.j -8.59529539e-02+0.j -2.48498285e-07+0.j 7.44967486e-07+0.j -1.49804491e-05+0.j 5.72906270e-06+0.j -3.41667207e-07+0.j 6.80335537e-07+0.j 8.59586851e-02-0.j -3.13850858e-07+0.j -2.25011991e-01+0.j 2.25001426e-01+0.j -8.94358758e-08+0.j 2.28147286e-07+0.j 2.25037314e-01-0.j -4.17190716e-01+0.j 4.04318359e-07+0.j 2.24985670e-01+0.j -5.80694794e-07+0.j -5.52937243e-07+0.j -3.65082459e-05+0.j -3.90497512e-07+0.j -8.59269962e-02+0.j 2.25025608e-01+0.j -2.98391414e-07+0.j -2.25025863e-01+0.j -3.04711511e-07+0.j -3.40211462e-07+0.j -2.99483126e-06+0.j 8.59452553e-02+0.j -2.16154325e-07+0.j -1.94828762e-07+0.j 7.01097394e-06-0.j 3.82073930e-07+0.j -1.82476211e-05+0.j -1.91093439e-05+0.j 3.20589139e-07+0.j]
In [8]:
Copied!
# Create XXZ Hamiltonian
hamiltonian = XXZ(nqubits=nqubits)
# Create VQE model
vqe = VQE(circuit, hamiltonian)
# Optimize starting from a random guess for the variational parameters
initial_parameters = np.random.uniform(0, 2 * np.pi, nqubits * (2 * nlayers + 1))
best, params, extra = vqe.minimize(initial_parameters, method='BFGS', compile=False)
# Create XXZ Hamiltonian
hamiltonian = XXZ(nqubits=nqubits)
# Create VQE model
vqe = VQE(circuit, hamiltonian)
# Optimize starting from a random guess for the variational parameters
initial_parameters = np.random.uniform(0, 2 * np.pi, nqubits * (2 * nlayers + 1))
best, params, extra = vqe.minimize(initial_parameters, method='BFGS', compile=False)
In [9]:
Copied!
params
params
Out[9]:
array([ 4.21062705e+00, 5.18951999e+00, 5.40577797e+00, -3.78845126e-02,
1.08247618e+00, 1.69902903e+00, 2.44463214e+00, 2.39224256e+00,
-1.53115517e+00, 4.46600560e+00, 2.56440926e+00, 4.92893526e+00,
3.14159185e+00, -1.57080238e+00, 5.58515962e+00, 4.87383133e+00,
3.85974314e+00, -7.39506208e-02, 4.01321429e+00, 6.28318875e+00,
3.79090966e+00, -3.65623802e-02, 1.76787872e+00, 2.28778269e+00,
2.72128607e+00, 7.85397559e+00, 6.28318789e+00, 3.39883611e+00,
2.39896560e+00, 2.97641751e+00, 3.67630303e+00, 4.71239184e+00,
1.57079018e+00, 1.78285777e+00, 4.10925257e+00, -2.52234689e-01,
-7.40548093e-02, 5.26009333e+00, 3.68658061e+00, 6.08494426e+00,
3.03432962e+00, 3.01018076e+00, 4.71238843e+00, 1.61179052e+00,
-5.64860693e-01, 4.71238928e+00, 4.01301849e-02, 5.73610282e-02,
3.14159431e+00, 6.28319782e+00, 4.31819200e-06, 3.14159249e+00,
4.71238986e+00, 4.71238910e+00])
In [7]:
Copied!
extra
extra
Out[7]:
message: Optimization terminated successfully.
success: True
status: 0
fun: -9.472135811881502
x: [ 2.731e+00 3.142e+00 ... 4.712e+00 4.712e+00]
nit: 246
jac: [ 5.960e-07 1.073e-06 ... 1.192e-07 -3.576e-07]
hess_inv: [[ 5.743e+00 -7.593e-01 ... -1.461e+00 -2.731e+00]
[-7.593e-01 3.133e+00 ... -1.272e+00 -1.327e+00]
...
[-1.461e+00 -1.272e+00 ... 3.191e+00 3.352e+00]
[-2.731e+00 -1.327e+00 ... 3.352e+00 4.776e+00]]
nfev: 14190
njev: 258
In [72]:
Copied!
extra
extra
Out[72]:
message: Optimization terminated successfully.
success: True
status: 0
fun: -9.47213586830712
x: [-1.998e-05 3.314e+00 ... 4.712e+00 7.854e+00]
nit: 283
jac: [-2.384e-06 -1.431e-06 ... 0.000e+00 -7.153e-07]
hess_inv: [[ 4.686e+00 -1.416e+00 ... -1.702e+00 -2.411e+00]
[-1.416e+00 1.165e+01 ... -6.208e-01 -1.005e+00]
...
[-1.702e+00 -6.208e-01 ... 4.317e+00 4.713e+00]
[-2.411e+00 -1.005e+00 ... 4.713e+00 6.355e+00]]
nfev: 16115
njev: 293
将算法的输出(量子比特的状态)与真实物理系统(如分子、磁性材料)的波函数联系起来,是整个过程的最终目的。这个联系是通过映射(Mapping) 建立的。
下面我们分步详解这个过程。
一、核心思想:建立映射关系¶
关键一步是,在问题开始时,我们就需要定义一个编码规则,将物理系统的自由度编码到量子比特的状态上。
物理系统的希尔伯特空间 ⟷ 量子比特的希尔伯特空间
一旦这个映射确立,量子计算机上制备出的量子态 |ψ_q⟩ 就直接对应于物理系统的波函数 |ψ_phy⟩。
二、具体步骤:从物理系统到量子比特¶
让我们以多电子系统(分子) 和自旋系统(海森堡模型) 这两个最典型的例子来说明。
案例一:多电子系统(量子化学)¶
目标是求解一个分子(如 H₂)的电子结构,即电子的波函数和能量。
选择基组:
- 首先,我们需要用一个有限的基组来展开电子的波函数。常用的是原子轨道基组(如 STO-3G)。假设我们有两个原子轨道,记为
|ϕ₀⟩和|ϕ₁⟩。
- 首先,我们需要用一个有限的基组来展开电子的波函数。常用的是原子轨道基组(如 STO-3G)。假设我们有两个原子轨道,记为
选择映射方式:
- 最常用的是 Jordan-Wigner 或 Bravyi-Kitaev 映射。这些映射规则将电子的占据情况编码到量子比特的状态上。
- 规则:每个量子比特代表一个原子轨道。
|0⟩表示该轨道没有被电子占据。|1⟩表示该轨道被一个电子占据。
- 对于 H₂ 分子,在最小基组(STO-3G)下,我们需要两个原子轨道,因此也需要两个量子比特。
建立联系:
- 物理系统的可能状态:
- 两个轨道都空着:
|00⟩(物理上不存在,因为H₂有2个电子) - 轨道0被占据,轨道1空着:
|10⟩(单激发态) - 轨道1被占据,轨道0空着:
|01⟩(单激发态) - 两个轨道都被占据:
|11⟩(双激发态)
- 两个轨道都空着:
- H₂ 分子的真实电子波函数就是这些基态的线性组合:
|ψ_phy⟩ = c₀|01⟩ + c₁|10⟩ + c₂|00⟩ + c₃|11⟩ - VQE 的输出:量子计算机最终会制备出一个双量子比特态:
|ψ_q⟩ = α|00⟩ + β|01⟩ + γ|10⟩ + δ|11⟩ - 二者的关联:由于我们使用了相同的映射规则,
|ψ_q⟩的状态向量 (α, β, γ, δ) 就直接是物理波函数|ψ_phy⟩的系数 (c₀, c₁, c₂, c₃) 在所选基组下的表示!β ≈ c₀γ ≈ c₁α ≈ c₂δ ≈ c₃
- 物理系统的可能状态:
提取物理信息:
- 一旦得到了这些系数,我们就可以计算电子密度分布、轨道占据数、键级等化学家关心的物理量。例如,
|β|² + |γ|²给出了电子处于单激发态的概率。
- 一旦得到了这些系数,我们就可以计算电子密度分布、轨道占据数、键级等化学家关心的物理量。例如,
案例二:自旋系统(海森堡模型)¶
目标是求解一维磁性链的基态波函数。
映射方式:
- 这个映射非常直观,几乎是一一对应的。
- 规则:每个量子比特直接代表一个格点上的自旋-1/2。
|0⟩(或|↑⟩)表示自旋向上。|1⟩(或|↓⟩)表示自旋向下。
建立联系:
- 对于一个有 N 个格点的链,物理系统的希尔伯特空间由
2^N个基矢张成,例如|↑↑↑⟩,|↑↑↓⟩,|↑↓↑⟩, ... - 物理系统的波函数是这些基矢的线性组合:
|ψ_phy⟩ = a|↑↑↑⟩ + b|↑↑↓⟩ + c|↑↓↑⟩ + ... - VQE 的输出:量子计算机制备出的 N-量子比特态为:
|ψ_q⟩ = α|000⟩ + β|001⟩ + γ|010⟩ + δ|011⟩ + ... - 二者的关联:由于映射是直接的,量子态的状态向量就是自旋波函数的系数!
α是所有自旋向上的概率幅。β是前两个自旋向上、最后一个自旋向下的概率幅。- 以此类推。
- 对于一个有 N 个格点的链,物理系统的希尔伯特空间由
提取物理信息:
- 局域磁化强度:测量第 i 个量子比特的
<Z_i>期望值。<Z_i> = +1表示自旋向上,-1表示向下,0表示处于量子涨落中。 - 两体关联函数:测量
〈Z_i Z_j〉可以判断自旋 i 和 j 是倾向于平行(正值)还是反平行(负值),从而判断磁有序的类型和关联长度。
- 局域磁化强度:测量第 i 个量子比特的
三、工作流程总结¶
整个从物理问题到量子解决方案的流程可以概括为以下步骤:
In [1]:
Copied!
# 安装:pip install graphviz
from graphviz import Digraph
# 安装:pip install graphviz
from graphviz import Digraph
In [5]:
Copied!
dot = Digraph(comment='VQE Flow')
dot.node('A', 'Physical System\n(Molecules, Materials)')
dot.node('B', 'Choose Mapping Rule\n(e.g., Jordan-Wigner)')
dot.node('C', 'Construct Hamiltonian')
dot.node('D', 'Run VQE Algorithm')
dot.node('E', 'Obtain Quantum State and Energy')
dot.node('F', 'Interpret Quantum State')
dot.node('G', 'Calculate Physical Observables')
dot.node('H', 'Compare with Experimental Data')
dot.edges(['AB', 'BC', 'CD', 'DE', 'EF', 'FG', 'GH'])
dot
dot = Digraph(comment='VQE Flow')
dot.node('A', 'Physical System\n(Molecules, Materials)')
dot.node('B', 'Choose Mapping Rule\n(e.g., Jordan-Wigner)')
dot.node('C', 'Construct Hamiltonian')
dot.node('D', 'Run VQE Algorithm')
dot.node('E', 'Obtain Quantum State and Energy')
dot.node('F', 'Interpret Quantum State')
dot.node('G', 'Calculate Physical Observables')
dot.node('H', 'Compare with Experimental Data')
dot.edges(['AB', 'BC', 'CD', 'DE', 'EF', 'FG', 'GH'])
dot
Out[5]:
重要说明¶
- 基组 truncation:在量子化学中,我们无法处理无限的轨道数。我们只能用有限数量的量子比特编码有限数量的轨道。这引入了误差,但可以通过增加基组大小(更多量子比特)来系统性地改善。
- 测量的意义:量子计算机输出的是概率幅(波函数系数),而不仅仅是经典概率。这使我们能够获得波函数的相位信息,这是经典方法难以高效处理的,也是量子优势的来源。
- 并非所有信息都需要:有时我们只关心能量(如基态能量),而不需要完整的波函数。VQE 通过测量期望值可以直接得到能量,而无需完全重构整个状态向量,这更加高效。
总而言之,算法的输出与物理系统的联系是通过我们在问题开始时人为定义的、一一对应的映射规则来实现的。量子比特的状态向量就是物理波函数在该映射规则所选基组下的系数。这使得我们可以从量子计算机的输出中直接读取和理解真实物理系统的量子态性质。