주 콘텐츠로 건너뛰기

인스턴스와 확장

이 챕터에서는 다음과 같은 여러 양자 변분 알고리즘을 다룹니다.

이 알고리즘들을 활용하면서, 가중치, 페널티, 과다 샘플링, 과소 샘플링 등 맞춤형 변분 알고리즘에 적용할 수 있는 여러 설계 아이디어를 배우게 됩니다. 이러한 개념을 직접 실험해 보고, 그 결과를 커뮤니티와 공유해 주세요.

Qiskit 패턴 프레임워크는 이 모든 알고리즘에 적용됩니다. 단, 단계별로 명시적으로 설명하는 것은 첫 번째 예제에서만 진행합니다.

변분 양자 고유값 해법 (VQE)

VQE는 가장 널리 사용되는 변분 양자 알고리즘 중 하나로, 다른 알고리즘들이 기반으로 삼는 템플릿을 제공합니다.

VQE가 참조 상태와 안사츠를 사용하여 비용 함수를 추정하고, 변분 파라미터를 통해 반복하는 방식을 보여주는 다이어그램.

1단계: 고전적 입력을 양자 문제로 매핑

이론적 구성

VQE의 구성은 간단합니다:

  • 참조 연산자 URU_R 준비
    • 0|0\rangle 상태에서 시작하여 참조 상태 ρ|\rho\rangle로 이동합니다.
  • 변분 폼 UV(θi,j)U_V(\vec\theta_{i,j})를 적용하여 안사츠 UA(θi,j)U_A(\vec\theta_{i,j}) 생성
    • ρ|\rho\rangle 상태에서 UV(θi,j)ρ=ψ(θi,j)U_V(\vec\theta_{i,j})|\rho\rangle = |\psi(\vec\theta_{i,j})\rangle로 이동합니다.
  • 유사한 문제가 있는 경우 i=0i=0에서 부트스트랩 (일반적으로 고전적 시뮬레이션 또는 샘플링으로 확인)
    • 각 옵티마이저는 서로 다른 방식으로 부트스트랩되며, 초기 파라미터 벡터 집합 Θ0:=θ0,jjJopt0\Theta_0 := \\{ {\vec\theta_{0,j} | j \in \mathcal{J}_\text{opt}^0} \\}을 생성합니다 (예: 초기 점 θ0\vec\theta_0으로부터).
  • 양자 컴퓨터에서 준비된 모든 상태에 대해 비용 함수 C(θi,j):=ψ(θ)H^ψ(θ)C(\vec\theta_{i,j}) := \langle \psi(\vec{\theta}) | \hat{H} | \psi(\vec{\theta})\rangle 평가.
  • 고전적 옵티마이저를 사용하여 다음 파라미터 집합 Θi+1\Theta_{i+1} 선택.
  • 수렴에 도달할 때까지 과정 반복.

이것은 비용 함수를 평가하는 단순한 고전적 최적화 루프입니다. 일부 옵티마이저는 기울기 계산, 다음 반복 결정, 또는 수렴 평가를 위해 여러 번의 평가가 필요할 수 있습니다.

다음 관측 가능량에 대한 예제입니다:

O^1=2II2XX+3YY3ZZ,\hat{O}_1 = 2 II - 2 XX + 3 YY - 3 ZZ,

구현

# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-ibm-runtime scipy
from qiskit import QuantumCircuit
from qiskit.quantum_info import SparsePauliOp
from qiskit.circuit.library import TwoLocal
import numpy as np

theta_list = (2 * np.pi * np.random.rand(1, 8)).tolist()
observable = SparsePauliOp.from_list([("II", 2), ("XX", -2), ("YY", 3), ("ZZ", -3)])

reference_circuit = QuantumCircuit(2)
reference_circuit.x(0)

variational_form = TwoLocal(
2,
rotation_blocks=["rz", "ry"],
entanglement_blocks="cx",
entanglement="linear",
reps=1,
)

ansatz = reference_circuit.compose(variational_form)

ansatz.decompose().draw("mpl")

이전 코드 셀의 출력

def cost_func_vqe(parameters, ansatz, hamiltonian, estimator):
"""Return estimate of energy from estimator

Parameters:
params (ndarray): Array of ansatz parameters
ansatz (QuantumCircuit): Parameterized ansatz circuit
hamiltonian (SparsePauliOp): Operator representation of Hamiltonian
estimator (Estimator): Estimator primitive instance

Returns:
float: Energy estimate
"""

estimator_job = estimator.run([(ansatz, hamiltonian, [parameters])])
estimator_result = estimator_job.result()[0]

cost = estimator_result.data.evs[0]
return cost
from qiskit.primitives import StatevectorEstimator

estimator = StatevectorEstimator()

이 비용 함수를 사용하여 최적 파라미터를 계산할 수 있습니다.

# SciPy minimizer routine
from scipy.optimize import minimize

x0 = np.ones(8)

result = minimize(
cost_func_vqe, x0, args=(ansatz, observable, estimator), method="COBYLA"
)

result
message: Optimization terminated successfully.
success: True
status: 1
fun: -5.999999982445723
x: [ 1.741e+00 9.606e-01 1.571e+00 2.115e-05 1.899e+00
1.243e+00 6.063e-01 6.063e-01]
nfev: 136
maxcv: 0.0

2단계: 양자 실행을 위한 문제 최적화

가장 여유 있는 Backend를 선택하고, qiskit_ibm_runtime에서 필요한 컴포넌트를 임포트합니다.

from qiskit_ibm_runtime import SamplerV2 as Sampler
from qiskit_ibm_runtime import EstimatorV2 as Estimator
from qiskit_ibm_runtime import Session, EstimatorOptions
from qiskit_ibm_runtime import QiskitRuntimeService

service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)
print(backend)
<IBMBackend('ibm_brisbane')>

최적화 레벨 3의 프리셋 패스 매니저를 사용하여 Circuit을 Transpile하고, 관측 가능량에 해당 레이아웃을 적용합니다.

from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager

pm = generate_preset_pass_manager(backend=backend, optimization_level=3)
isa_ansatz = pm.run(ansatz)
isa_observable = observable.apply_layout(layout=isa_ansatz.layout)

3단계: Qiskit Runtime 프리미티브를 사용한 실행

이제 IBM Quantum® 하드웨어에서 계산을 실행할 준비가 되었습니다. 비용 함수 최소화는 반복 횟수가 매우 많기 때문에, Runtime Session을 시작합니다. 이렇게 하면 큐에서 한 번만 기다리면 됩니다. 작업이 실행되기 시작하면, 파라미터가 업데이트된 각 반복은 즉시 실행됩니다.

x0 = np.ones(8)

estimator_options = EstimatorOptions(resilience_level=1, default_shots=10_000)

with Session(backend=backend) as session:
estimator = Estimator(mode=session, options=estimator_options)

result = minimize(
cost_func_vqe,
x0,
args=(isa_ansatz, isa_observable, estimator),
method="COBYLA",
options={"maxiter": 200, "disp": True},
)
session.close()
print(result)

4단계: 후처리 및 고전적 형식으로 결과 반환

최소화 루틴이 성공적으로 종료되었음을 확인할 수 있으며, 이는 COBYLA 고전적 옵티마이저의 기본 허용 오차에 도달했음을 의미합니다. 더 정밀한 결과가 필요하다면 더 작은 허용 오차를 지정할 수 있습니다. 위의 시뮬레이터로 얻은 결과와 비교했을 때 결과가 몇 퍼센트 차이가 나므로, 실제로 그럴 필요가 있을 수 있습니다.

얻어진 x 값은 비용 함수를 최소화하는 파라미터에 대한 현재 최선의 추정값입니다. 더 높은 정밀도를 위해 반복하는 경우, 처음에 사용한 x0(1의 벡터) 대신 해당 값을 사용해야 합니다.

마지막으로, 최적화 과정에서 함수가 96번 평가되었음을 확인할 수 있습니다. 이는 최적화 단계 수와 다를 수 있는데, 기울기 추정 시와 같이 일부 옵티마이저는 단일 단계에서 여러 번의 함수 평가를 필요로 하기 때문입니다.

부분 공간 탐색 VQE (SSVQE)

SSVQE는 VQE의 변형으로, 고유값이 {λ0,λ1,...,λN1}\{\lambda_0, \lambda_1,...,\lambda_{N-1}\}이고 NkN\geq k인 관측 가능량 H^\hat{H}의 처음 kk개 고유값을 구할 수 있습니다. 일반성을 잃지 않고 λ0<λ1<...<λN1\lambda_0<\lambda_1<...<\lambda_{N-1}로 가정합니다. SSVQE는 가중치가 가장 큰 항의 최적화를 우선시하는 가중치를 추가하는 새로운 아이디어를 도입합니다.

부분 공간 탐색 VQE가 변분 알고리즘의 컴포넌트를 사용하는 방식을 보여주는 다이어그램.

이 알고리즘을 구현하려면 kk개의 상호 직교하는 참조 상태 {ρj}j=0k1\{ |\rho_j\rangle \}_{j=0}^{k-1}가 필요합니다. 즉, j,l<kj,l<k에 대해 ρjρl=δjl\langle \rho_j | \rho_l \rangle = \delta_{jl}이어야 합니다. 이 상태들은 Pauli 연산자를 사용하여 구성할 수 있습니다. 이 알고리즘의 비용 함수는 다음과 같습니다:

C(θ):=j=0k1wjρjUV(θ)H^UV(θ)ρj:=j=0k1wjψj(θ)H^ψj(θ)\begin{aligned} C(\vec{\theta}) & := \sum_{j=0}^{k-1} w_j \langle \rho_j | U_{V}^{\dagger}(\vec{\theta})\hat{H} U_{V}(\vec{\theta})|\rho_j \rangle \\[1mm] & := \sum_{j=0}^{k-1} w_j \langle \psi_{j}(\vec{\theta}) | \hat{H} | \psi_{j}(\vec{\theta}) \rangle \\[1mm] \end{aligned}

여기서 wjw_jj<l<kj<l<k이면 wj>wlw_j>w_l을 만족하는 임의의 양수이며, UV(θ)U_V(\vec{\theta})는 사용자 정의 변분 폼입니다.

SSVQE 알고리즘은 서로 다른 고유값에 해당하는 고유 상태가 상호 직교한다는 사실에 기반합니다. 구체적으로, UV(θ)ρjU_V(\vec{\theta})|\rho_j\rangleUV(θ)ρlU_V(\vec{\theta})|\rho_l\rangle의 내적은 다음과 같이 표현할 수 있습니다:

ρjUV(θ)UV(θ)ρl=ρjIρl=ρjρl=δjl\begin{aligned} \langle \rho_j | U_{V}^{\dagger}(\vec{\theta})U_{V}(\vec{\theta})|\rho_l \rangle & = \langle \rho_j | I |\rho_l \rangle \\[1mm] & = \langle \rho_j | \rho_l \rangle \\[1mm] & = \delta_{jl} \end{aligned}

첫 번째 등식은 UV(θ)U_{V}(\vec{\theta})가 양자 연산자이므로 유니타리하기 때문에 성립합니다. 마지막 등식은 참조 상태 ρj|\rho_j\rangle의 직교성 때문에 성립합니다. 유니타리 변환을 통해 직교성이 보존된다는 사실은 양자 정보 과학에서 표현되는 정보 보존 원리와 깊이 연관되어 있습니다. 이 관점에서, 비유니타리 변환은 정보가 손실되거나 주입되는 과정을 나타냅니다.

가중치 wjw_j는 모든 상태가 고유 상태가 되도록 보장하는 데 도움이 됩니다. 가중치가 충분히 다를 경우, 가장 큰 가중치(즉, w0w_0)를 가진 항이 최적화 과정에서 다른 항들보다 우선시됩니다. 그 결과, 상태 UV(θ)ρ0U_{V}(\vec{\theta})|\rho_0 \rangleλ0\lambda_0에 해당하는 고유 상태가 됩니다. {UV(θ)ρj}j=0k1\{ U_{V}(\vec{\theta})|\rho_j\rangle \}_{j=0}^{k-1}가 상호 직교하기 때문에, 나머지 상태들은 이에 직교하며, 따라서 고유값 {λ1,...,λN1}\{\lambda_1,...,\lambda_{N-1}\}에 해당하는 부분 공간 내에 포함됩니다.

나머지 항들에 동일한 논리를 적용하면, 다음 우선순위는 가중치 w1w_1을 가진 항이 됩니다. 따라서 UV(θ)ρ1U_{V}(\vec{\theta})|\rho_1 \rangleλ1\lambda_1에 해당하는 고유 상태가 되고, 다른 항들은 {λ2,...,λN1}\{\lambda_2,...,\lambda_{N-1}\}의 고유 공간에 포함됩니다.

귀납적으로 추론하면, 0j<k0\leq j < k에 대해 UV(θ)ρjU_{V}(\vec{\theta})|\rho_j \rangleλj\lambda_j의 근사 고유 상태가 됩니다.

이론적 구성

SSVQE의 구성은 다음과 같이 요약할 수 있습니다:

  • 유니타리 U_R을 kk개의 서로 다른 계산 기저 상태에 적용하여 여러 참조 상태 준비
    • 이 알고리즘은 j,l<kj,l<k에 대해 ρjρl=δjl\langle \rho_j | \rho_l \rangle = \delta_{jl}을 만족하는 kk개의 상호 직교 참조 상태 {ρj}j=0k1\{ |\rho_j\rangle \}_{j=0}^{k-1}가 필요합니다.
  • 각 참조 상태에 변분 폼 UV(θi,j)U_V(\vec\theta_{i,j})를 적용하여 안사츠 UA(θi,j)U_A(\vec\theta_{i,j}) 생성.
  • 유사한 문제가 있는 경우 i=0i=0에서 부트스트랩 (일반적으로 고전적 시뮬레이션 또는 샘플링으로 확인).
  • 양자 컴퓨터에서 준비된 모든 상태에 대해 비용 함수 C(θi,j):=j=0k1wjψj(θ)H^ψj(θ)C(\vec\theta_{i,j}) := \sum_{j=0}^{k-1} w_j \langle \psi_{j}(\vec{\theta}) | \hat{H} | \psi_{j}(\vec{\theta}) \rangle 평가.
    • 이는 관측 가능량에 대한 기댓값 ψj(θ)H^ψj(θ)\langle \psi_{j}(\vec{\theta}) | \hat{H} | \psi_{j}(\vec{\theta}) \rangle을 계산하고 그 결과에 wjw_j를 곱하는 것으로 분리할 수 있습니다.
    • 이후, 비용 함수는 가중된 모든 기댓값의 합을 반환합니다.
  • 고전적 옵티마이저를 사용하여 다음 파라미터 집합 Θi+1\Theta_{i+1} 결정.
  • 수렴에 도달할 때까지 위 단계를 반복.

평가에서 SSVQE의 비용 함수를 재구성하게 되지만, 솔루션을 이해하는 데 도움이 되는 코드 스니펫을 먼저 살펴보겠습니다:

import numpy as np

def cost_func_ssvqe(
params, initialized_anastz_list, weights, ansatz, hamiltonian, estimator
):
# """Return estimate of energy from estimator

# Parameters:
# params (ndarray): Array of ansatz parameters
# initialized_anastz_list (list QuantumCircuit): Array of initialised ansatz with reference
# weights (list): List of weights
# ansatz (QuantumCircuit): Parameterized ansatz circuit
# hamiltonian (SparsePauliOp): Operator representation of Hamiltonian
# estimator (Estimator): Estimator primitive instance

# Returns:
# float: Weighted energy estimate
# """

energies = []

# Define SSVQE

weighted_energy_sum = np.dot(energies, weights)
return weighted_energy_sum

Variational Quantum Deflation (VQD)

VQD는 VQE를 확장하여, 고유값이 {λ0,λ1,...,λN1}\{\lambda_0, \lambda_1,...,\lambda_{N-1}\}인 관측량 H^\hat{H}에서 (NkN\geq k인 경우) 첫 번째 고유값 하나만이 아니라 처음 kk개의 고유값을 구하는 반복적인 방법입니다. 이 절의 나머지 부분에서는 일반성을 잃지 않고 λ0λ1...λN1\lambda_0\leq\lambda_1\leq...\leq\lambda_{N-1}이라고 가정합니다. VQD는 최적화 과정을 안내하기 위한 페널티 비용의 개념을 도입합니다.

A diagram showing how VQD uses the components of a variational algorithm. VQD는 각 겹침 항의 비용 기여도를 균형 있게 조정하기 위해 β\beta로 표기되는 페널티 항을 도입합니다. 이 페널티 항은 직교성이 달성되지 않을 경우 최적화 과정에 불이익을 주는 역할을 합니다. 이 제약을 부과하는 이유는, 관측량(에르미트 연산자)의 서로 다른 고유값에 대응하는 고유 상태는 항상 상호 직교하거나(또는 축퇴나 반복 고유값의 경우 그렇게 만들 수 있기 때문입니다. 따라서 λ0\lambda_0에 해당하는 고유 상태와의 직교성을 강제함으로써, 나머지 고유값 {λ1,λ2,...,λN1}\{\lambda_1, \lambda_2,..., \lambda_{N-1}\}에 대응하는 부분 공간에서 효과적으로 최적화를 수행합니다. 여기서 λ1\lambda_1은 나머지 고유값 중 가장 낮은 고유값이므로, 변분 정리를 통해 새로운 문제의 최적해를 구할 수 있습니다.

VQD의 기본 아이디어는 VQE를 그대로 사용하여 어떤 최적 매개변수 벡터 θ0\vec{\theta^0}에 대해 최저 고유값 λ0:=C0(θ0)CVQE(θ0)\lambda_0 := C_0(\vec\theta^0) \equiv C_\text{VQE}(\vec\theta^0)와 이에 대응하는 (근사) 고유 상태 ψ(θ0)|\psi(\vec{\theta^0})\rangle를 구하는 것입니다. 그런 다음 다음 고유값 λ1>λ0\lambda_1 > \lambda_0를 구하기 위해, 비용 함수 C0(θ):=ψ(θ)H^ψ(θ)C_0(\vec{\theta}) := \langle \psi(\vec{\theta}) | \hat{H} | \psi(\vec{\theta})\rangle를 최소화하는 대신 다음을 최적화합니다:

C1(θ):=C0(θ)+β0ψ(θ)ψ(θ0)2C_1(\vec{\theta}) := C_0(\vec{\theta})+ \beta_0 |\langle \psi(\vec{\theta})| \psi(\vec{\theta^0})\rangle |^2

양의 값 β0\beta_0는 이상적으로 λ1λ0\lambda_1-\lambda_0보다 커야 합니다.

이를 통해 새로운 비용 함수가 도입되는데, 이는 제약 문제로 볼 수 있습니다. 즉, 상태가 이전에 구한 ψ(θ0)|\psi(\vec{\theta^0})\rangle에 직교해야 한다는 제약 하에 CVQE(θ)=ψ(θ)H^ψ(θ)C_\text{VQE}(\vec{\theta}) = \langle \psi(\vec{\theta}) | \hat{H} | \psi(\vec{\theta})\rangle를 최소화하며, β0\beta_0는 제약이 만족되지 않을 경우 페널티 항으로 작용합니다.

또는 이 새로운 문제를 다음 관측량에 대한 VQE 실행으로 해석할 수 있습니다:

H1^:=H^+β0ψ(θ0)ψ(θ0)C1(θ)=ψ(θ)H1^ψ(θ),\hat{H_1} := \hat{H} + \beta_0 |\psi(\vec{\theta^0})\rangle \langle \psi(\vec{\theta^0})| \quad \Rightarrow \quad C_1(\vec{\theta}) = \langle \psi(\vec{\theta}) | \hat{H_1} | \psi(\vec{\theta})\rangle,

새로운 문제의 해가 ψ(θ1)|\psi(\vec{\theta^1})\rangle라고 가정할 때, H^\hat{H}(H1^\hat{H_1}이 아닌)의 기대값은 ψ(θ1)H^ψ(θ1)=λ1 \langle \psi(\vec{\theta^1}) | \hat{H} | \psi(\vec{\theta^1})\rangle = \lambda_1이 되어야 합니다. 세 번째 고유값 λ2\lambda_2를 구하기 위한 최적화 비용 함수는 다음과 같습니다:

C2(θ):=C1(θ)+β1ψ(θ)ψ(θ1)2C_2(\vec{\theta}) := C_1(\vec{\theta}) + \beta_1 |\langle \psi(\vec{\theta})| \psi(\vec{\theta^1})\rangle |^2

여기서 β1\beta_1은 해 상태가 ψ(θ0)|\psi(\vec{\theta^0})\rangleψ(θ1)|\psi(\vec{\theta^1})\rangle 모두에 대해 직교성을 강제할 만큼 충분히 큰 양의 상수입니다. 이는 이 요건을 충족하지 않는 탐색 공간의 상태에 페널티를 부과하여 탐색 공간을 효과적으로 제한합니다. 따라서 새로운 문제의 최적해는 λ2\lambda_2에 대응하는 고유 상태가 됩니다.

이전 경우와 마찬가지로, 이 새로운 문제도 다음 관측량을 사용하는 VQE로 해석할 수 있습니다:

H2^:=H1^+β1ψ(θ1)ψ(θ1)C2(θ)=ψ(θ)H2^ψ(θ).\hat{H_2} := \hat{H_1} + \beta_1 |\psi(\vec{\theta^1})\rangle \langle \psi(\vec{\theta^1})| \quad \Rightarrow \quad C_2(\vec{\theta}) = \langle \psi(\vec{\theta}) | \hat{H_2} | \psi(\vec{\theta})\rangle.

이 새로운 문제의 해가 ψ(θ2)|\psi(\vec{\theta^2})\rangle라면, H^\hat{H}(H2^\hat{H_2}이 아닌)의 기대값은 ψ(θ2)H^ψ(θ2)=λ2 \langle \psi(\vec{\theta^2}) | \hat{H} | \psi(\vec{\theta^2})\rangle = \lambda_2가 되어야 합니다. 유추적으로, kk번째 고유값 λk1\lambda_{k-1}을 구하려면 다음 비용 함수를 최소화합니다:

Ck1(θ):=Ck2(θ)+βk2ψ(θ)ψ(θk2)2,C_{k-1}(\vec{\theta}) := C_{k-2}(\vec{\theta}) + \beta_{k-2} |\langle \psi(\vec{\theta})| \psi(\vec{\theta^{k-2}})\rangle |^2,

θj\vec{\theta^j}ψ(θj)H^ψ(θj)=λj,j<k\langle \psi(\vec{\theta^j}) | \hat{H} | \psi(\vec{\theta^j})\rangle = \lambda_j, \forall j<k가 되도록 정의했다는 점을 기억하세요. 이 문제는 C(θ)=ψ(θ)H^ψ(θ)C(\vec{\theta}) = \langle \psi(\vec{\theta}) | \hat{H} | \psi(\vec{\theta})\rangle를 최소화하되 상태가 ψ(θj);j0,,k1|\psi(\vec{\theta^j})\rangle ; \forall j \in {0, \cdots, k-1}에 직교해야 한다는 제약을 갖는 문제와 동등하며, 이를 통해 탐색 공간을 고유값 {λk1,,λN1}\{\lambda_{k-1},\cdots,\lambda_{N-1}\}에 대응하는 부분 공간으로 제한합니다.

이 문제는 다음 관측량을 사용하는 VQE와 동등합니다:

H^k1:=H^k2+βk2ψ(θk2)ψ(θk2)Ck1(θ)=ψ(θ)H^k1ψ(θ),\hat{H}_{k-1} := \hat{H}_{k-2} + \beta_{k-2} |\psi(\vec{\theta^{k-2}})\rangle \langle \psi(\vec{\theta^{k-2}})| \quad \Rightarrow \quad C_{k-1}(\vec{\theta}) = \langle \psi(\vec{\theta}) | \hat{H}_{k-1} | \psi(\vec{\theta})\rangle,

이 과정에서 알 수 있듯이, kk번째 고유값을 구하려면 이전 k1k-1개 고유값의 (근사) 고유 상태가 필요하므로 VQE를 총 kk번 실행해야 합니다. 따라서 VQD의 비용 함수는 다음과 같습니다:

Ck(θ)=ψ(θ)H^ψ(θ)+j=0k1βjψ(θ)ψ(θj)2C_k(\vec{\theta}) = \langle \psi(\vec{\theta}) | \hat{H} | \psi(\vec{\theta})\rangle + \sum_{j=0}^{k-1}\beta_j |\langle \psi(\vec{\theta})| \psi(\vec{\theta^j})\rangle |^2

이론적 구성

VQD의 구성을 요약하면 다음과 같습니다:

  • 참조 연산자 URU_R 준비
  • 참조 상태에 변분 형식 UV(θi,j)U_V(\vec\theta_{i,j})를 적용하여 다음 앤사츠 UA(θi,j)U_A(\vec\theta_{i,j}) 생성
  • 유사한 문제가 있는 경우 i=0i=0에서 부트스트랩(일반적으로 고전 시뮬레이션 또는 샘플링으로 찾음).
  • kk개의 들뜬 상태와 각 겹침 항의 겹침 페널티를 정의하는 β\beta 배열을 계산하는 비용 함수 Ck(θ)C_k(\vec{\theta}) 평가.
    • kk에 대해 관측량의 기대값 ψj(θ)H^ψj(θ)\langle \psi_{j}(\vec{\theta}) | \hat{H} | \psi_{j}(\vec{\theta}) \rangle 계산
    • 페널티 j=0k1βjψ(θ)ψ(θj)2\sum_{j=0}^{k-1}\beta_j |\langle \psi(\vec{\theta})| \psi(\vec{\theta^j})\rangle |^2 계산.
    • 비용 함수는 이 두 항의 합을 반환해야 합니다
  • 고전 최적화기를 사용하여 다음 매개변수 집합 Θi+1\Theta_{i+1} 선택.
  • 수렴에 도달할 때까지 이 과정을 반복합니다.

구현

이 구현에서는 겹침 페널티 함수를 만들겠습니다. 이 페널티는 각 반복에서 비용 함수에 사용됩니다. 이 과정은 각 들뜬 상태에 대해 반복됩니다.

from qiskit.circuit.library import TwoLocal

ansatz = TwoLocal(2, rotation_blocks=["ry", "rz"], entanglement_blocks="cz", reps=1)

ansatz.decompose().draw("mpl")

Output of the previous code cell

먼저, 상태 충실도(두 상태 간의 겹침 비율)를 계산하는 함수를 설정합니다. 이를 VQD의 페널티로 사용합니다:

import numpy as np

def calculate_overlaps(ansatz, prev_circuits, parameters, sampler):
def create_fidelity_circuit(circuit_1, circuit_2):
"""
Constructs the list of fidelity circuits to be evaluated.
These circuits represent the state overlap between pairs of input circuits,
and their construction depends on the fidelity method implementations.
"""

if len(circuit_1.clbits) > 0:
circuit_1.remove_final_measurements()
if len(circuit_2.clbits) > 0:
circuit_2.remove_final_measurements()

circuit = circuit_1.compose(circuit_2.inverse())
circuit.measure_all()
return circuit

overlaps = []

for prev_circuit in prev_circuits:
fidelity_circuit = create_fidelity_circuit(ansatz, prev_circuit)
sampler_job = sampler.run([(fidelity_circuit, parameters)])
meas_data = sampler_job.result()[0].data.meas

counts_0 = meas_data.get_int_counts().get(0, 0)
shots = meas_data.num_shots
overlap = counts_0 / shots
overlaps.append(overlap)

return np.array(overlaps)

이제 VQD의 비용 함수를 작성할 차례입니다. 앞서 바닥 상태만 계산했을 때와 마찬가지로, Estimator 프리미티브를 사용하여 최저 에너지 상태를 결정합니다. 그러나 위에서 설명한 것처럼, 이제 더 높은 에너지 상태의 직교성을 보장하기 위한 페널티 항을 추가합니다. 즉, 각 새로운 들뜬 상태에 대해 현재 변분 상태와 이미 찾은 낮은 에너지 고유 상태 간의 겹침에 대한 페널티가 추가됩니다.

def cost_func_vqd(
parameters, ansatz, prev_states, step, betas, estimator, sampler, hamiltonian
):
estimator_job = estimator.run([(ansatz, hamiltonian, [parameters])])

total_cost = 0

if step > 1:
overlaps = calculate_overlaps(ansatz, prev_states, parameters, sampler)
total_cost = np.sum(
[np.real(betas[state] * overlap) for state, overlap in enumerate(overlaps)]
)

estimator_result = estimator_job.result()[0]

value = estimator_result.data.evs[0] + total_cost

return value

특히 위의 비용 함수가 calculate_overlaps 함수를 참조하며, 이 함수는 실제로 새로운 양자 Circuit을 생성한다는 점에 주목하세요. 실제 하드웨어에서 실행하려면 그 새로운 Circuit도 선택한 Backend에서 실행되도록 최적의 방법으로 트랜스파일되어야 합니다. 트랜스파일은 calculate_overlaps 또는 cost_func_vqd 함수에 내장되지 않았습니다. 이 추가적인(그리고 조건부) 트랜스파일을 직접 코드에 내장해 보세요 - 하지만 다음 강의에서 이 부분도 처리해 드릴 것입니다.

이 강의에서는 Statevector Sampler와 Statevector Estimator를 사용하여 VQD 알고리즘을 실행합니다:

from qiskit.primitives import StatevectorEstimator as Estimator

sampler = Sampler()
estimator = Estimator()

추정할 관측량을 도입합니다. 다음 강의에서는 분자의 들뜬 상태와 같은 물리적 맥락을 추가할 것입니다. 이 관측량을 특정 분자나 원자에 맞게 선택되지 않았더라도 들뜬 상태를 가질 수 있는 시스템의 해밀토니안으로 생각하면 도움이 될 수 있습니다.

from qiskit.quantum_info import SparsePauliOp

observable = SparsePauliOp.from_list([("II", 2), ("XX", -2), ("YY", 3), ("ZZ", -3)])

여기서 계산하려는 총 상태 수(바닥 상태와 들뜬 상태, k)와 직교해야 하는 상태 벡터 간의 겹침에 대한 페널티(betas)를 설정합니다. betas를 너무 높거나 낮게 선택했을 때의 결과는 다음 강의에서 좀 더 살펴볼 것입니다. 지금은 아래에 제공된 값을 그대로 사용합니다. 매개변수의 초기값으로 모두 0을 사용합니다. 실제 계산에서는 시스템에 대한 지식이나 이전 계산을 바탕으로 더 영리한 초기 매개변수를 사용하는 것이 좋습니다.

k = 3
betas = [33, 33, 33]
x0 = np.zeros(8)

이제 계산을 실행할 수 있습니다:

from scipy.optimize import minimize

prev_states = []
prev_opt_parameters = []
eigenvalues = []

for step in range(1, k + 1):
if step > 1:
prev_states.append(ansatz.assign_parameters(prev_opt_parameters))

result = minimize(
cost_func_vqd,
x0,
args=(ansatz, prev_states, step, betas, estimator, sampler, observable),
method="COBYLA",
options={
"maxiter": 200,
},
)
print(result)

prev_opt_parameters = result.x
eigenvalues.append(result.fun)
message: Optimization terminated successfully.
success: True
status: 1
fun: -5.999999979545955
x: [-5.150e-01 -5.452e-02 -1.571e+00 -2.853e-05 2.671e-01
-2.672e-01 -8.509e-01 -8.510e-01]
nfev: 131
maxcv: 0.0
message: Optimization terminated successfully.
success: True
status: 1
fun: 4.024550284767612
x: [-3.745e-01 1.041e+00 8.637e-01 1.202e+00 -8.847e-02
1.181e-02 7.611e-01 -3.006e-01]
nfev: 110
maxcv: 0.0
message: Optimization terminated successfully.
success: True
status: 1
fun: 5.608925562838559
x: [-2.670e-01 1.280e+00 1.070e+00 -8.031e-01 -1.524e-01
-6.956e-02 7.018e-01 1.514e+00]
nfev: 90
maxcv: 0.0

비용 함수에서 얻은 값은 각각 약 -6.00, 4.02, 5.61입니다. 이 결과에서 중요한 점은 함수 값이 증가하고 있다는 것입니다. 만약 첫 번째 들뜬 상태가 제약 없는 초기 바닥 상태 계산보다 에너지가 낮게 나왔다면, 코드 어딘가에 오류가 있다는 것을 의미합니다.

x의 값은 이러한 비용(에너지)에 대응하는 상태 벡터를 생성한 매개변수입니다.

마지막으로, 세 개의 최소화 모두 고전 최적화기(여기서는 COBYLA)의 기본 허용 오차 내에서 수렴되었다는 점을 언급합니다. 각각 131, 110, 90번의 함수 평가가 필요했습니다.

Quantum Sampling Regression (QSR)

VQE의 주요 문제 중 하나는 각 단계의 매개변수를 구하기 위해 양자 컴퓨터를 여러 번 호출해야 한다는 것입니다(예: kk, k1k-1 등). 이는 양자 장치 접근이 대기열로 관리될 때 특히 문제가 됩니다. Session을 사용하여 여러 반복 호출을 그룹화할 수 있지만, 다른 방법으로 샘플링을 활용하는 것도 가능합니다. 더 많은 고전 자원을 활용함으로써 단 한 번의 호출로 전체 최적화 과정을 완료할 수 있습니다. 바로 이것이 Quantum Sampling Regression이 활용되는 지점입니다. 양자 컴퓨터에 대한 접근이 여전히 공급 부족/수요 과잉 상품이기 때문에, 이 트레이드오프는 현재 많은 연구에서 실용적이고 편리하다고 생각합니다. 이 접근 방식은 가용한 모든 고전적 능력을 활용하면서도 시뮬레이션에서는 나타나지 않는 양자 계산의 내부 작동 및 고유한 특성을 포착합니다.

A diagram showing how QSR uses the components of a variational algorithm.

QSR의 아이디어는 비용 함수 C(θ):=ψ(θ)H^ψ(θ)C(\theta) := \langle \psi(\theta) | \hat{H} | \psi(\theta)\rangle를 다음과 같이 푸리에 급수로 표현할 수 있다는 것입니다:

C(θ):=ψ(θ)H^ψ(θ):=a0+k=1S[akcos(kθ)+bksin(kθ)]\begin{aligned} C(\vec{\theta}) & := \langle \psi(\theta) | \hat{H} | \psi(\theta)\rangle \\[1mm] & := a_0 + \sum_{k=1}^S[a_k\cos(k\theta)+ b_k\sin(k\theta)] \\[1mm] \end{aligned}

원래 함수의 주기성과 대역폭에 따라 집합 SS는 유한하거나 무한할 수 있습니다. 이 논의에서는 무한하다고 가정합니다. 다음 단계는 비용 함수 C(θ)C(\theta)를 여러 번 샘플링하여 푸리에 계수 {a0,ak,bk}k=1S\{a_0, a_k, b_k\}_{k=1}^S를 구하는 것입니다. 구체적으로, 미지수가 2S+12S+1개이므로 비용 함수를 2S+12S+1번 샘플링해야 합니다.

2S+12S+1개의 매개변수 값 {θ1,...,θ2S+1}\{\theta_1,...,\theta_{2S+1}\}에 대해 비용 함수를 샘플링하면 다음 연립방정식을 얻을 수 있습니다:

(1cos(θ1)sin(θ1)cos(2θ1)...sin(Sθ1)1cos(θ2)sin(θ2)cos(2θ2)sin(Sθ2)1cos(θ2S+1)sin(θ2S+1)cos(2θ2S+1)sin(Sθ2S+1))(a0a1b1a2bS)=(C(θ1)C(θ2)C(θ2S+1)),\begin{pmatrix} 1 & \cos(\theta_1) & \sin(\theta_1) & \cos(2\theta_1) & ... & \sin(S\theta_1) \\ 1 & \cos(\theta_2) & \sin(\theta_2) & \cos(2\theta_2) & \cdots & \sin(S\theta_2)\\ \vdots & \vdots & \vdots & \vdots & \ddots & \vdots\\ 1 & \cos(\theta_{2S+1}) & \sin(\theta_{2S+1}) & \cos(2\theta_{2S+1}) & \cdots & \sin(S\theta_{2S+1}) \end{pmatrix} \begin{pmatrix} a_0 \\ a_1 \\ b_1 \\ a_2 \\ \vdots \\ b_S \end{pmatrix} = \begin{pmatrix} C(\theta_1) \\ C(\theta_2) \\ \vdots \\ C(\theta_{2S+1}) \end{pmatrix},

이를 다음과 같이 다시 쓸 수 있습니다:

Fa=c.Fa=c.

실제로 비용 함수 값 cc는 정확하지 않기 때문에 이 연립방정식은 일반적으로 일관성이 없습니다. 따라서 왼쪽에 FF^\dagger를 곱하여 정규화하는 것이 좋으며, 그 결과는 다음과 같습니다:

FFa=Fc.F^\dagger Fa = F^\dagger c.

이 새로운 연립방정식은 항상 일관성이 있으며, 그 해는 원래 문제의 최소 제곱 해입니다. 매개변수가 하나가 아닌 kk개이고, 각 매개변수 θi\theta^ii1,...,ki \in {1,...,k}에 대해 고유한 SiS_i를 가질 경우, 필요한 총 샘플 수는 다음과 같습니다:

T=i=1k(2Si+1)i=1k(2Smax+1)=(2Smax+1)n,T=\prod_{i=1}^k(2S_i+1)\leq \prod_{i=1}^k(2S_{max}+1) = (2S_{max}+1)^n,

여기서 Smax=maxi(Si)S_{\max} = \max_i(S_i)입니다. 또한 SmaxS_{\max}를 (추론하는 대신) 조정 가능한 매개변수로 설정하면 다음과 같은 새로운 가능성이 열립니다:

  • **과샘플링(Over-sampling)**으로 정확도 향상.
  • **언더샘플링(Under-sampling)**으로 런타임 오버헤드 감소 또는 지역 최솟값 제거를 통한 성능 향상.

이론적 구성

QSR의 구성을 요약하면 다음과 같습니다:

  • 참조 연산자 URU_R 준비.
    • 0|0\rangle 상태에서 참조 상태 ρ|\rho\rangle로 이동합니다.
  • 앤사츠 UA(θi,j)U_A(\vec\theta_{i,j})를 생성하기 위해 변분 형식 UV(θi,j)U_V(\vec\theta_{i,j}) 적용.
    • 앤사츠의 각 매개변수와 관련된 대역폭을 결정합니다. 상한으로도 충분합니다.
  • 유사한 문제가 있는 경우 i=0i=0에서 부트스트랩(일반적으로 고전 시뮬레이션 또는 샘플링으로 찾음).
  • 비용 함수 C(θ):=a0+k=1S[akcos(kθ)+bksin(kθ)]C(\vec\theta) := a_0 + \sum_{k=1}^S[a_k\cos(k\theta)+ b_k\sin(k\theta)]를 적어도 TT번 샘플링.
    • T=i=1k(2Si+1)i=1k(2Smax+1)=(2Smax+1)nT=\prod_{i=1}^k(2S_i+1)\leq \prod_{i=1}^k(2S_{max}+1) = (2S_{max}+1)^n
    • TT를 조정하여 속도 대 정확도를 균형 있게 조정하기 위해 과샘플링/언더샘플링 여부 결정.
  • 샘플에서 푸리에 계수 계산(즉, 정규화된 선형 연립방정식 풀기).
  • 고전 머신에서 결과 회귀 함수의 전역 최솟값 해결.

요약

이 강의에서는 사용 가능한 여러 변분 인스턴스에 대해 배웠습니다:

  • 일반 구성
  • 비용 함수를 조정하기 위한 가중치 및 페널티 도입
  • 속도 대 정확도의 트레이드오프를 위한 언더샘플링 vs 과샘플링 탐색

이러한 아이디어를 적용하여 문제에 맞는 맞춤형 변분 알고리즘을 만들 수 있습니다. 결과를 커뮤니티와 공유해 주세요. 다음 강의에서는 변분 알고리즘을 사용하여 응용 문제를 해결하는 방법을 탐구할 것입니다.