Skip to main content
IBM Quantum Platform

시간 진화 회로에 대한 근사 양자 컴파일링

예상 소요 시간: 헤론 프로세서 기준 15초 (참고: 이는 단지 추정치일 뿐입니다.) (실행 시간은 다를 수 있습니다.)


학습 성과

  • AQC-Tensor Qiskit 애드온을 사용하여 심층 트로터 회로를 얕은 안자츠 회로로 압축하는 방법
  • 트로터 회로로부터 매개변수화된 가설을 생성하고 텐서 네트워크(MPS) 기법을 사용하여 그 매개변수를 최적화하는 방법
  • 압축 회로의 목표 진화 과정에 대한 정확도를 평가하고 양자 하드웨어에서 실행하는 방법

전제조건


배경

이 튜토리얼에서는 Qiskit을 사용하여 텐서 네트워크 기반 근사 양자 컴파일링 (AQC-Tensor)을 구현하고, 이를 통해 양자 회로의 성능을 향상시키는 방법을 설명합니다. AQC-Tensor는 시뮬레이션 정확도를 유지하면서 깊은 트로터 회로를 더 얕고 하드웨어에 더 적합한 회로로 압축합니다.

AQC-Tensor의 작동 원리

kk 개의 트로터 단계를 사용하여 총 시간 tt 동안 해밀토니안 HH 을 시뮬레이션한다고 가정하자. 트로터 회로의 전체 내용은 다음과 같습니다:

Ufull=[UTrotter(t/k)]kU_{\text{full}} = \left[U_{\text{Trotter}}(t/k)\right]^k

단순한 접근 방식은 회로 깊이를 적정 수준으로 유지하기 위해 트로터 단계를 적게 사용하지만, 이로 인해 상당한 트로터 오차가 발생한다. AQC-Tensor는 정확도와 깊이를 분리함으로써 이러한 상충 관계를 해결합니다:

  1. 대상 회로(고정밀도, 심층): 동일한 진화 시간에 대해 단계가 많은 트로터 회로(예: 10k10k )를 구성한다. 이 회로는 트로터 오차가 훨씬 적지만, 하드웨어로 구현하기에는 너무 복잡합니다. 이것은 고전적으로 행렬 곱 상태(MPS)로만 시뮬레이션되기 때문에, 깊이는 문제가 되지 않습니다.

  2. Ansatz 회로(저차원, 매개변수화됨): 단일 단계 트로터 회로와 동일한 구조를 가진 매개변수화 회로 V(θ)V(\theta) 를 정의합니다. V(θinit)=UTrotter(t/k)V(\theta_{\text{init}}) = U_{\text{Trotter}}(t/k) 가 되도록 초기 설정한 다음, θ\theta 를 반복적으로 최적화하여 V(θ)V(\theta) 가 고정밀도 목표 상태를 가능한 한 정확하게 재현하도록 한다.

그 결과, 단일 트로터 단계의 깊이를 유지하면서도 여러 단계에 해당하는 정확도를 달성하는 회로가 탄생했으며, 이를 통해 가까운 시일 내에 양자 하드웨어를 구현하는 것이 가능해졌다.

AQC-Tensor를 사용할 때

AQC-Tensor는 다음과 같은 경우에 가장 효과적입니다:

  • 회로 깊이가 하드웨어 일관성 시간을 초과합니다. 트로터 시뮬레이션에 장치가 지원할 수 있는 것보다 더 많은 트로터 단계가 필요한 경우, AQC-Tensor는 이 진화 과정을 더 얕은 회로로 압축할 수 있습니다.
  • 양자 얽힘은 여전히 고전적인 방법으로 다루기 가능하다. 시간 진화 상태에서의 총 얽힘은 주로 진화 시간 tt 에 달려 있으며, 트로터 단계 수 kk 에는 크게 좌우되지 않습니다. 즉, 10k10k 단계로 구성된 대상 회로는 kk 단계로 구성된 회로와 비교하여 MPS로 표현하는 데 일반적으로 더 어렵지 않습니다. 단, tt 가 충분히 짧아 결합 차원을 관리 가능한 수준으로 유지할 수 있는 경우에 한합니다.
  • 자연스러운 접근 방식이 존재한다. 이 접근법은 트로터 회로의 구조를 반영하고 있으므로, 명확하게 정의된 초기 매개변수를 갖춘 물리적으로 타당한 출발점을 제공하며, 임의의 변분적 접근법에서 흔히 발생하는 수렴 문제를 피할 수 있다.

이 접근 방식은 일반적인 회로 압축 방식과는 대조적입니다. AQC-Tensor는 임의의 유니터리 연산을 더 적은 게이트 수로 근사화하려고 시도하는 대신, 동일한 게이트 구조를 유지한 채 매개변수를 최적화하여 트로터 오차를 줄입니다. 자세한 내용은 AQC-Tensor 문서를 참조하십시오.

이 튜토리얼에서는 해밀토니안 정의, 트로터 회로 생성, 텐서 네트워크 최적화를 통한 압축, 그리고 IBM Quantum® 하드웨어에서 결과 실행에 이르는 전체 상태 준비(state-preparation) AQC-Tensor 워크플로를 단계별로 안내합니다.


요구사항

이 튜토리얼을 시작하기 전에 다음이 설치되어 있는지 확인하세요:

  • Qiskit SDK v2.0 또는 그 이후 버전이며, 시각화 기능을 지원합니다
  • Qiskit Runtime v0.22 이상 (pip install qiskit-ibm-runtime)
  • AQC-텐서 키스킷 애드온 (pip install 'qiskit-addon-aqc-tensor[aer,quimb-jax]')

설정

import numpy as np
import quimb.tensor
import datetime
import matplotlib.pyplot as plt

from scipy.linalg import expm
from scipy.optimize import OptimizeResult, minimize

from qiskit.quantum_info import SparsePauliOp, Pauli
from qiskit.transpiler import CouplingMap
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit import QuantumCircuit
from qiskit.synthesis import SuzukiTrotter

from qiskit_addon_utils.problem_generators import (
    generate_time_evolution_circuit,
)
from qiskit_addon_aqc_tensor.ansatz_generation import (
    generate_ansatz_from_circuit,
)
from qiskit_addon_aqc_tensor.objective import MaximizeStateFidelity
from qiskit_addon_aqc_tensor.simulation.quimb import QuimbSimulator
from qiskit_addon_aqc_tensor.simulation import tensornetwork_from_circuit
from qiskit_addon_aqc_tensor.simulation import compute_overlap

from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import EstimatorV2 as Estimator
from qiskit_ibm_runtime.fake_provider import FakeKyiv

from rustworkx.visualization import graphviz_draw

소규모 시뮬레이터 예시

이 섹션에서는 10개 사이트 시스템을 사용하여 AQC-Tensor 워크플로를 단계별로 설명합니다. 우리는 스핀 상호작용과 자기적 특성을 연구하기 위해 널리 사용되는 모델인 10-사이트 XXZ 스핀 사슬의 역학을 시뮬레이션한다.

해밀토니안은 다음과 같습니다:

H^XXZ=i=1L1Ji,(i+1)(XiX(i+1)+YiY(i+1)+2ZiZ(i+1)),\hat{\mathcal{H}}_{XXZ} = \sum_{i=1}^{L-1} J_{i,(i+1)}\left(X_i X_{(i+1)}+Y_i Y_{(i+1)}+ 2\cdot Z_i Z_{(i+1)} \right) \, ,

여기서 Ji,(i+1)J_{i,(i+1)} 는 변 (i,i+1)(i, i+1)L=10L=10 에 대한 무작위 계수이다.

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

이 단계에서는 다음을 수행합니다:

  1. 해밀토니안, 관측량 및 초기 상태를 정의하라.
  2. 나중에 비교할 수 있도록 고전적인 방법으로 정확한 기대값을 구하십시오.
  3. AQC-Tensor를 사용하여 고정밀도 트로터 회로(AQC 타겟)를 생성하고, 이를 낮은 깊이(low-depth)의 안자츠로 압축합니다.

해밀토니안, 관측량 및 초기 상태를 설정한다

# L is the number of sites in the 1D spin chain
L = 10

# Generate the coupling map
edge_list = [(i - 1, i) for i in range(1, L)]
even_edges = edge_list[::2]
odd_edges = edge_list[1::2]
coupling_map = CouplingMap(edge_list)

# Generate random coefficients for our XXZ Hamiltonian
np.random.seed(0)
Js = np.random.rand(L - 1) + 0.5 * np.ones(L - 1)
hamiltonian = SparsePauliOp(Pauli("I" * L))
for i, edge in enumerate(even_edges + odd_edges):
    hamiltonian += SparsePauliOp.from_sparse_list(
        [
            ("XX", (edge), Js[i] / 2),
            ("YY", (edge), Js[i] / 2),
            ("ZZ", (edge), Js[i]),
        ],
        num_qubits=L,
    )

# Generate a ZZ observable between the two middle qubits
observable = SparsePauliOp.from_sparse_list(
    [("ZZ", (L // 2 - 1, L // 2), 1.0)], num_qubits=L
)

# Generate an initial Néel state |1010101010⟩
initial_state_circuit = QuantumCircuit(L)
for i in range(L):
    if i % 2:
        initial_state_circuit.x(i)

print("Hamiltonian:", hamiltonian)
print("Observable:", observable)
graphviz_draw(coupling_map.graph, method="circo")

Output:

Hamiltonian: SparsePauliOp(['IIIIIIIIII', 'IIIIIIIIXX', 'IIIIIIIIYY', 'IIIIIIIIZZ', 'IIIIIIXXII', 'IIIIIIYYII', 'IIIIIIZZII', 'IIIIXXIIII', 'IIIIYYIIII', 'IIIIZZIIII', 'IIXXIIIIII', 'IIYYIIIIII', 'IIZZIIIIII', 'XXIIIIIIII', 'YYIIIIIIII', 'ZZIIIIIIII', 'IIIIIIIXXI', 'IIIIIIIYYI', 'IIIIIIIZZI', 'IIIIIXXIII', 'IIIIIYYIII', 'IIIIIZZIII', 'IIIXXIIIII', 'IIIYYIIIII', 'IIIZZIIIII', 'IXXIIIIIII', 'IYYIIIIIII', 'IZZIIIIIII'],
              coeffs=[1.        +0.j, 0.52440675+0.j, 0.52440675+0.j, 1.0488135 +0.j,
 0.60759468+0.j, 0.60759468+0.j, 1.21518937+0.j, 0.55138169+0.j,
 0.55138169+0.j, 1.10276338+0.j, 0.52244159+0.j, 0.52244159+0.j,
 1.04488318+0.j, 0.4618274 +0.j, 0.4618274 +0.j, 0.9236548 +0.j,
 0.57294706+0.j, 0.57294706+0.j, 1.14589411+0.j, 0.46879361+0.j,
 0.46879361+0.j, 0.93758721+0.j, 0.6958865 +0.j, 0.6958865 +0.j,
 1.391773  +0.j, 0.73183138+0.j, 0.73183138+0.j, 1.46366276+0.j])
Observable: SparsePauliOp(['IIIIZZIIII'],
              coeffs=[1.+0.j])
Output of the previous code cell

정확한 기대값을 구하라

이 정도 규모의 시스템에 대해서는 행렬 지수 연산을 사용하여 시간 경과에 따른 기대값을 직접 정확히 계산할 수 있습니다. 이는 AQC 회로의 정확도를 평가하기 위한 기준 데이터 역할을 합니다.

aqc_evolution_time = 0.2

# Each baseline Trotter step covers dt = aqc_evolution_time / 3
# The subsequent (uncompressed) step covers 1 additional dt
subsequent_evolution_time = aqc_evolution_time / 3
total_evolution_time = aqc_evolution_time + subsequent_evolution_time

# Compute exact expectation value via matrix exponentiation
H_matrix = hamiltonian.to_matrix()
U_exact = expm(-1j * H_matrix * total_evolution_time)

# Build the initial state vector (Néel state)
initial_state_vec = np.zeros(2**L)
state_idx = sum(2**i for i in range(L) if i % 2)
initial_state_vec[state_idx] = 1.0

# Evolve and compute expectation value
evolved_state = U_exact @ initial_state_vec
obs_matrix = observable.to_matrix()
exact_expval = (evolved_state.conj() @ obs_matrix @ evolved_state).real

print(f"AQC evolution time: {aqc_evolution_time}")
print(f"Subsequent evolution time: {subsequent_evolution_time:.6f}")
print(f"Total evolution time: {total_evolution_time:.6f}")
print(f"Exact expectation value: {exact_expval:.6f}")

Output:

AQC evolution time: 0.2
Subsequent evolution time: 0.066667
Total evolution time: 0.266667
Exact expectation value: -0.700899

AQC 대상 회로 생성

이제 AQC의 대상 역할을 할 트로터 회로를 구성해 보겠습니다. 이 회로는 높은 정확도를 위해 다수의 트로터 단계(32단계)를 사용합니다. 이 모델은 하드웨어에서 실행되는 것이 아니라 MPS로만 고전적으로 시뮬레이션될 것이기 때문에, 깊은 깊이는 문제가 되지 않습니다.

aqc_target_num_trotter_steps = 32

aqc_target_circuit = initial_state_circuit.copy()
aqc_target_circuit.compose(
    generate_time_evolution_circuit(
        hamiltonian,
        synthesis=SuzukiTrotter(reps=aqc_target_num_trotter_steps),
        time=aqc_evolution_time,
    ),
    inplace=True,
)

가설, 초기 매개변수, 후속 회로 및 기준 회로를 생성합니다

다음으로, AQC 대상과 동일한 진화 시간을 가지되 트로터 단계는 훨씬 적은(단 한 단계뿐인) “우수한” 회로를 구성합니다. 이 회로를 에 generate_ansatz_from_circuit 전달하면 다음과 같은 결과가 반환됩니다:

  1. 동일한 2-큐비트 연결 구조를 갖는 일반적인 매개변수화 앤자츠 회로.
  2. 안자츠(ansatz)에 연결했을 때 입력 회로를 재현하는 초기 매개변수.

또한 다음을 구성합니다:

  • AQC-Tensor 초기 상태 튜토리얼의 접근 방식을 따라, AQC 최적화된 부분 뒤에 (압축되지 않은 상태로) 추가될 트로터 단계 하나를 포함하는 후속 회로입니다.
  • 전체 실행 시간(aqc_evolution_time + subsequent_evolution_time) 동안 4단계의 트로터 단계를 사용하는 기본 트로터 회로입니다. 이는 비교 대상으로 사용되며, AQC가 없는 하드웨어에서 실행될 경우의 결과를 나타냅니다. AQC 접근법(압축 단계 3회 + 비압축 단계 1회)은 더 낮은 깊이에서 더 높은 정확도를 달성합니다.
aqc_ansatz_num_trotter_steps = 1

aqc_good_circuit = initial_state_circuit.copy()
aqc_good_circuit.compose(
    generate_time_evolution_circuit(
        hamiltonian,
        synthesis=SuzukiTrotter(reps=aqc_ansatz_num_trotter_steps),
        time=aqc_evolution_time,
    ),
    inplace=True,
)

aqc_ansatz, aqc_initial_parameters = generate_ansatz_from_circuit(
    aqc_good_circuit
)

# Subsequent circuit: 1 non-compressed Trotter step appended after AQC
subsequent_num_trotter_steps = 1
subsequent_circuit = generate_time_evolution_circuit(
    hamiltonian,
    synthesis=SuzukiTrotter(reps=subsequent_num_trotter_steps),
    time=subsequent_evolution_time,
)

# Baseline Trotter circuit: 4 Trotter steps over total evolution time, no AQC
baseline_num_trotter_steps = 4
baseline_circuit = initial_state_circuit.copy()
baseline_circuit.compose(
    generate_time_evolution_circuit(
        hamiltonian,
        synthesis=SuzukiTrotter(reps=baseline_num_trotter_steps),
        time=total_evolution_time,
    ),
    inplace=True,
)

print(
    f"Target circuit:      depth {aqc_target_circuit.depth(lambda x: x.operation.num_qubits == 2)}"
)
print(
    f"Baseline circuit:    depth {baseline_circuit.depth(lambda x: x.operation.num_qubits == 2)} ({baseline_num_trotter_steps} Trotter steps, time={total_evolution_time:.4f})"
)
print(
    f"Subsequent circuit:  depth {subsequent_circuit.depth(lambda x: x.operation.num_qubits == 2)} ({subsequent_num_trotter_steps} Trotter step, time={subsequent_evolution_time:.4f})"
)
print(
    f"Ansatz circuit:      depth {aqc_ansatz.depth(lambda x: x.operation.num_qubits == 2)}, with {len(aqc_initial_parameters)} parameters"
)
aqc_ansatz.draw("mpl", fold=-1)

Output:

Target circuit:      depth 384
Baseline circuit:    depth 48 (4 Trotter steps, time=0.2667)
Subsequent circuit:  depth 12 (1 Trotter step, time=0.0667)
Ansatz circuit:      depth 3, with 156 parameters
Output of the previous code cell

텐서 네트워크 시뮬레이션을 설정하고 대상 MPS를 구축한다

우리는 quimb 행렬곱 상태(MPS) 회로 시뮬레이터를 사용하며, JAX를 통해 기울기 기반 최적화를 위한 자동 미분 기능을 제공합니다. 그런 다음 목표 상태에 대한 MPS 표현을 구축하고, 초기 가설과 목표 사이의 초기 충실도를 평가합니다. 문제 사례는 비교적 작은 예시이기 때문에, 초기 정확도는 상당히 높은 수준에서 시작됩니다.

simulator_settings = QuimbSimulator(
    quimb.tensor.CircuitMPS, autodiff_backend="jax"
)

aqc_target_mps = tensornetwork_from_circuit(
    aqc_target_circuit, simulator_settings
)
print("Target MPS maximum bond dimension:", aqc_target_mps.psi.max_bond())

good_mps = tensornetwork_from_circuit(aqc_good_circuit, simulator_settings)
starting_fidelity = abs(compute_overlap(good_mps, aqc_target_mps)) ** 2
print(f"Starting fidelity: {starting_fidelity:.6f}")

Output:

Target MPS maximum bond dimension: 5
Starting fidelity: 0.998246

안자츠 매개변수 최적화

우리는 L-BFGS-B 최적화 알고리즘을 사용하여 비용 함수를 MaximizeStateFidelity 최소화합니다. 최적화기는 초기 가정 회로와 목표 MPS 간의 일치도를 극대화하기 위해 초기 가정 매개변수를 반복적으로 조정합니다.

aqc_stopping_fidelity = 1
aqc_max_iterations = 500

stopping_point = 1.0 - aqc_stopping_fidelity
objective = MaximizeStateFidelity(
    aqc_target_mps, aqc_ansatz, simulator_settings
)


def callback(intermediate_result: OptimizeResult):
    fidelity = 1 - intermediate_result.fun
    print(
        f"{datetime.datetime.now()} Intermediate result: Fidelity {fidelity:.8f}"
    )
    if intermediate_result.fun < stopping_point:
        raise StopIteration


result = minimize(
    objective,
    aqc_initial_parameters,
    method="L-BFGS-B",
    jac=True,
    options={"maxiter": aqc_max_iterations},
    callback=callback,
)
if result.status not in (0, 1, 99):
    raise RuntimeError(
        f"Optimization failed: {result.message} (status={result.status})"
    )

print(f"Done after {result.nit} iterations.")
aqc_final_parameters = result.x

Output:

2026-05-18 13:14:49.731596 Intermediate result: Fidelity 0.99952882
2026-05-18 13:14:49.734425 Intermediate result: Fidelity 0.99958531
2026-05-18 13:14:49.737101 Intermediate result: Fidelity 0.99960093
2026-05-18 13:14:49.739813 Intermediate result: Fidelity 0.99961046
2026-05-18 13:14:49.742969 Intermediate result: Fidelity 0.99962560
2026-05-18 13:14:49.745916 Intermediate result: Fidelity 0.99964395
2026-05-18 13:14:49.748615 Intermediate result: Fidelity 0.99968150
2026-05-18 13:14:49.753684 Intermediate result: Fidelity 0.99970569
2026-05-18 13:14:49.756208 Intermediate result: Fidelity 0.99973788
2026-05-18 13:14:49.759067 Intermediate result: Fidelity 0.99975385
2026-05-18 13:14:49.762321 Intermediate result: Fidelity 0.99976458
2026-05-18 13:14:49.765526 Intermediate result: Fidelity 0.99977661
2026-05-18 13:14:49.768496 Intermediate result: Fidelity 0.99978663
2026-05-18 13:14:49.771278 Intermediate result: Fidelity 0.99980236
2026-05-18 13:14:49.773735 Intermediate result: Fidelity 0.99981607
2026-05-18 13:14:49.776339 Intermediate result: Fidelity 0.99982811
2026-05-18 13:14:49.779177 Intermediate result: Fidelity 0.99985827
2026-05-18 13:14:49.782243 Intermediate result: Fidelity 0.99988354
2026-05-18 13:14:49.784904 Intermediate result: Fidelity 0.99991608
2026-05-18 13:14:49.787737 Intermediate result: Fidelity 0.99993336
2026-05-18 13:14:49.790414 Intermediate result: Fidelity 0.99993956
2026-05-18 13:14:49.793029 Intermediate result: Fidelity 0.99994421
2026-05-18 13:14:49.795585 Intermediate result: Fidelity 0.99994743
2026-05-18 13:14:49.835045 Intermediate result: Fidelity 0.99994791
2026-05-18 13:14:49.839786 Intermediate result: Fidelity 0.99994803
2026-05-18 13:14:49.842403 Intermediate result: Fidelity 0.99994898
2026-05-18 13:14:49.873779 Intermediate result: Fidelity 0.99994898
Done after 27 iterations.

최종 AQC 회로를 조립하십시오

최적화된 매개변수를 확보한 후, 이를 가설에 대입하고 그 뒤에 이어지는 (압축되지 않은) 트로터 단계를 추가합니다. 이렇게 구성된 회로는 압축된 트로터 단계 하나와 압축되지 않은 단계 하나를 합친 깊이를 가지지만, 압축된 부분은 32개의 트로터 단계에 해당하는 정확도를 근사적으로 구현합니다.

aqc_final_circuit = aqc_ansatz.assign_parameters(aqc_final_parameters)
aqc_final_circuit.compose(subsequent_circuit, inplace=True)
aqc_final_circuit.draw("mpl", fold=-1)

Output:

Output of the previous code cell

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

이 소규모 예제에서는 로컬에서 하드웨어 실행을 시뮬레이션하기 위해 가상의 백엔드(FakeKyiv)를 사용합니다. 우리는 AQC로 최적화된 회로(aqc_final_circuit)와 기준 트로터 회로(전체 진화 시간 동안 baseline_circuit4단계의 트로터 단계를 수행하며, AQC 미적용)를 모두 백엔드의 명령어 집합 아키텍처(ISA)로 변환하며, 회로 깊이를 더욱 줄이기 위해 를 적용합니다 optimization_level=3 .

backend = FakeKyiv()

pass_manager = generate_preset_pass_manager(
    backend=backend, optimization_level=3
)

# Transpile the AQC-optimized circuit (compressed + subsequent step)
isa_circuit = pass_manager.run(aqc_final_circuit)
isa_observable = observable.apply_layout(isa_circuit.layout)
print(
    "AQC circuit depth:",
    isa_circuit.depth(lambda x: x.operation.num_qubits == 2),
)

# Transpile the baseline Trotter circuit (no AQC optimization)
isa_baseline_circuit = pass_manager.run(baseline_circuit)
isa_baseline_observable = observable.apply_layout(isa_baseline_circuit.layout)
print(
    "Baseline Trotter circuit depth:",
    isa_baseline_circuit.depth(lambda x: x.operation.num_qubits == 2),
)

Output:

AQC circuit depth: 15
Baseline Trotter circuit depth: 27

3단계: Qiskit primitives 명령어로 실행합니다

우리는 가짜 백엔드를 사용하는 프라이머리트를 EstimatorV2 통해 AQC 최적화 회로와 기준 트로터 회로를 모두 실행하고, 각각에 대해 ZZ 관측량을 측정합니다.

estimator = Estimator(backend)

# Run both circuits
aqc_result = estimator.run([(isa_circuit, isa_observable)]).result()
baseline_result = estimator.run(
    [(isa_baseline_circuit, isa_baseline_observable)]
).result()

4단계: 후처리 수행 및 원하는 클래식 형식으로 결과 반환

두 실행 결과에서 기대값을 추출하여 정확한 결과와 비교한다. 기준 트로터 회로는 동일한 회로 깊이에서 AQC를 적용하지 않았을 때의 결과를 보여주는 반면, AQC 회로는 텐서 네트워크 최적화를 통해 얻어진 개선 효과를 보여줍니다.

aqc_expval = aqc_result[0].data.evs.tolist()
baseline_expval = baseline_result[0].data.evs.tolist()

print(f"Exact:              {exact_expval:.4f}")
print(
    f"Baseline Trotter:   {baseline_expval:.4f}, |\u0394| = {np.abs(exact_expval - baseline_expval):.4f}  (depth {isa_baseline_circuit.depth(lambda x: x.operation.num_qubits == 2)}, {baseline_num_trotter_steps} steps)"
)
print(
    f"AQC (3+1):          {aqc_expval:.4f}, |\u0394| = {np.abs(exact_expval - aqc_expval):.4f}  (depth {isa_circuit.depth(lambda x: x.operation.num_qubits == 2)}, compressed+subsequent)"
)

Output:

Exact:              -0.7009
Baseline Trotter:   -0.5400, |Δ| = 0.1609  (depth 27, 4 steps)
AQC (3+1):          -0.5728, |Δ| = 0.1281  (depth 15, compressed+subsequent)
plt.style.use("seaborn-v0_8")

labels = [
    f"Baseline Trotter\n({baseline_num_trotter_steps} steps, depth {isa_baseline_circuit.depth(lambda x: x.operation.num_qubits == 2)})",
    f"AQC (3+1)\n(depth {isa_circuit.depth(lambda x: x.operation.num_qubits == 2)})",
]
values = [baseline_expval, aqc_expval]
colors = ["tab:orange", "tab:blue"]

plt.figure(figsize=(8, 5))
bars = plt.bar(labels, values, color=colors, width=0.5)
plt.axhline(
    y=exact_expval,
    color="tab:green",
    linestyle="--",
    linewidth=2,
    label=f"Exact ({exact_expval:.4f})",
)
plt.ylabel("Expected Value")
plt.title(
    "AQC-Tensor (3 compressed + 1 uncompressed) vs Baseline Trotter (10-site XXZ)"
)
plt.legend()
for bar in bars:
    y_val = bar.get_height()
    plt.text(
        bar.get_x() + bar.get_width() / 2.0,
        y_val,
        f"{y_val:.4f}",
        ha="center",
        va="bottom" if y_val >= 0 else "top",
    )
plt.axhline(y=0, color="black", linewidth=0.3)
plt.tight_layout()
plt.show()

Output:

Output of the previous code cell

대규모 하드웨어 예시

이제 50개 사이트로 구성된 XXZ 모델로 확장하여, 보다 현실적인 규모의 문제에서 AQC-Tensor의 성능을 보여드리겠습니다. 작업 흐름은 소규모 예제와 동일합니다. AQC를 통해 세 개의 트로터 단계를 압축하고, 압축되지 않은 단계를 하나 추가합니다.

이 정도 규모의 시스템에서는 행렬 지수 연산이 사실상 불가능하므로( 2502^{50} 차원), 전체 시간에 걸쳐 진화한 고정밀 MPS를 사용하여 기준 기대값을 직접 계산합니다.

1~4단계 통합

# -------------------------Step 1-------------------------

# Define the 50-site spin chain
L = 50
edge_list = [(i - 1, i) for i in range(1, L)]
even_edges = edge_list[::2]
odd_edges = edge_list[1::2]
coupling_map = CouplingMap(edge_list)

# Random XXZ Hamiltonian
np.random.seed(0)
Js = np.random.rand(L - 1) + 0.5 * np.ones(L - 1)
hamiltonian = SparsePauliOp(Pauli("I" * L))
for i, edge in enumerate(even_edges + odd_edges):
    hamiltonian += SparsePauliOp.from_sparse_list(
        [
            ("XX", (edge), Js[i] / 2),
            ("YY", (edge), Js[i] / 2),
            ("ZZ", (edge), Js[i]),
        ],
        num_qubits=L,
    )

observable = SparsePauliOp.from_sparse_list(
    [("ZZ", (L // 2 - 1, L // 2), 1.0)], num_qubits=L
)

# Initial Néel state
initial_state_circuit = QuantumCircuit(L)
for i in range(L):
    if i % 2:
        initial_state_circuit.x(i)

# Time parameters
aqc_evolution_time = 0.2
subsequent_evolution_time = aqc_evolution_time / 3
total_evolution_time = aqc_evolution_time + subsequent_evolution_time

# AQC target circuit (high-accuracy, 32 Trotter steps for AQC portion)
aqc_target_num_trotter_steps = 32

aqc_target_circuit = initial_state_circuit.copy()
aqc_target_circuit.compose(
    generate_time_evolution_circuit(
        hamiltonian,
        synthesis=SuzukiTrotter(reps=aqc_target_num_trotter_steps),
        time=aqc_evolution_time,
    ),
    inplace=True,
)

# Generate ansatz from 1-step Trotter circuit
aqc_good_circuit = initial_state_circuit.copy()
aqc_good_circuit.compose(
    generate_time_evolution_circuit(
        hamiltonian,
        synthesis=SuzukiTrotter(reps=1),
        time=aqc_evolution_time,
    ),
    inplace=True,
)

aqc_ansatz, aqc_initial_parameters = generate_ansatz_from_circuit(
    aqc_good_circuit
)

# Subsequent circuit: 1 non-compressed Trotter step
subsequent_circuit = generate_time_evolution_circuit(
    hamiltonian,
    synthesis=SuzukiTrotter(reps=1),
    time=subsequent_evolution_time,
)

# Baseline Trotter circuit: 4 Trotter steps over total evolution time, no AQC
baseline_num_trotter_steps = 4
baseline_circuit = initial_state_circuit.copy()
baseline_circuit.compose(
    generate_time_evolution_circuit(
        hamiltonian,
        synthesis=SuzukiTrotter(reps=baseline_num_trotter_steps),
        time=total_evolution_time,
    ),
    inplace=True,
)
print(
    f"Target circuit:  depth {aqc_target_circuit.depth(lambda x: x.operation.num_qubits == 2)}"
)
print(
    f"Ansatz circuit:  depth {aqc_ansatz.depth(lambda x: x.operation.num_qubits == 2)}, with {len(aqc_initial_parameters)} parameters"
)
print(
    f"Subsequent circuit: depth {subsequent_circuit.depth(lambda x: x.operation.num_qubits == 2)}"
)
print(
    f"Baseline circuit:   depth {baseline_circuit.depth(lambda x: x.operation.num_qubits == 2)} ({baseline_num_trotter_steps} steps, time={total_evolution_time:.4f})"
)

# Build target MPS and compute reference expectation value
simulator_settings = QuimbSimulator(
    quimb.tensor.CircuitMPS, autodiff_backend="jax"
)
aqc_target_mps = tensornetwork_from_circuit(
    aqc_target_circuit, simulator_settings
)
print("Target MPS maximum bond dimension:", aqc_target_mps.psi.max_bond())

# For the reference expectation value, we need the full evolution (AQC + subsequent)
# Build a high-accuracy full circuit for MPS reference
full_target_circuit = initial_state_circuit.copy()
full_target_circuit.compose(
    generate_time_evolution_circuit(
        hamiltonian,
        synthesis=SuzukiTrotter(reps=aqc_target_num_trotter_steps),
        time=total_evolution_time,
    ),
    inplace=True,
)
full_target_mps = tensornetwork_from_circuit(
    full_target_circuit, simulator_settings
)
exact_expval = full_target_mps.local_expectation(
    quimb.pauli("Z") & quimb.pauli("Z"), (L // 2 - 1, L // 2)
).real.item()
print(f"Reference expectation value (from MPS): {exact_expval:.6f}")

# Optimize ansatz parameters
objective = MaximizeStateFidelity(
    aqc_target_mps, aqc_ansatz, simulator_settings
)


def callback(intermediate_result: OptimizeResult):
    fidelity = 1 - intermediate_result.fun
    print(
        f"{datetime.datetime.now()} Intermediate result: Fidelity {fidelity:.8f}"
    )


result = minimize(
    objective,
    aqc_initial_parameters,
    method="L-BFGS-B",
    jac=True,
    options={"maxiter": 500},
    callback=callback,
)
if result.status not in (0, 1, 99):
    raise RuntimeError(
        f"Optimization failed: {result.message} (status={result.status})"
    )
print(f"Done after {result.nit} iterations.")

# Assemble the final AQC circuit: optimized ansatz + subsequent Trotter step
aqc_final_circuit = aqc_ansatz.assign_parameters(result.x)
aqc_final_circuit.compose(subsequent_circuit, inplace=True)

# -------------------------Step 2-------------------------

service = QiskitRuntimeService()
backend = service.least_busy(min_num_qubits=127)
print(backend)

pass_manager = generate_preset_pass_manager(
    backend=backend, optimization_level=3
)
isa_circuit = pass_manager.run(aqc_final_circuit)
isa_observable = observable.apply_layout(isa_circuit.layout)
print(
    "AQC circuit depth:",
    isa_circuit.depth(lambda x: x.operation.num_qubits == 2),
)

# Also transpile the baseline Trotter circuit (4 Trotter steps, no AQC)
isa_baseline_circuit = pass_manager.run(baseline_circuit)
isa_baseline_observable = observable.apply_layout(isa_baseline_circuit.layout)
print(
    "Baseline Trotter circuit depth:",
    isa_baseline_circuit.depth(lambda x: x.operation.num_qubits == 2),
)

# -------------------------Step 3-------------------------

# Submit both circuits in a single job
estimator = Estimator(backend)
estimator.options.environment.job_tags = ["TUT_AQCTE"]

job = estimator.run(
    [
        (isa_circuit, isa_observable),
        (isa_baseline_circuit, isa_baseline_observable),
    ]
)
print("Job ID:", job.job_id())

Output:

Target circuit:  depth 385
Ansatz circuit:  depth 7, with 816 parameters
Subsequent circuit: depth 12
Baseline circuit:   depth 49 (4 steps, time=0.2667)
Target MPS maximum bond dimension: 5
Reference expectation value (from MPS): -0.738669
2026-05-18 13:02:11.219150 Intermediate result: Fidelity 0.99795732
2026-05-18 13:02:11.232256 Intermediate result: Fidelity 0.99822481
2026-05-18 13:02:11.245160 Intermediate result: Fidelity 0.99829520
2026-05-18 13:02:11.257765 Intermediate result: Fidelity 0.99832379
2026-05-18 13:02:11.270280 Intermediate result: Fidelity 0.99836416
2026-05-18 13:02:11.284116 Intermediate result: Fidelity 0.99840073
2026-05-18 13:02:11.296856 Intermediate result: Fidelity 0.99846863
2026-05-18 13:02:11.309602 Intermediate result: Fidelity 0.99865244
2026-05-18 13:02:11.322012 Intermediate result: Fidelity 0.99872665
2026-05-18 13:02:11.334195 Intermediate result: Fidelity 0.99892335
2026-05-18 13:02:11.346570 Intermediate result: Fidelity 0.99901045
2026-05-18 13:02:11.359202 Intermediate result: Fidelity 0.99907181
2026-05-18 13:02:11.371511 Intermediate result: Fidelity 0.99911125
2026-05-18 13:02:11.383870 Intermediate result: Fidelity 0.99918585
2026-05-18 13:02:11.396184 Intermediate result: Fidelity 0.99921504
2026-05-18 13:02:11.408543 Intermediate result: Fidelity 0.99924936
2026-05-18 13:02:11.422557 Intermediate result: Fidelity 0.99929226
2026-05-18 13:02:11.436275 Intermediate result: Fidelity 0.99933099
2026-05-18 13:02:11.449511 Intermediate result: Fidelity 0.99935792
2026-05-18 13:02:11.462093 Intermediate result: Fidelity 0.99937925
2026-05-18 13:02:11.475783 Intermediate result: Fidelity 0.99940690
2026-05-18 13:02:11.490254 Intermediate result: Fidelity 0.99944409
2026-05-18 13:02:11.503292 Intermediate result: Fidelity 0.99946840
2026-05-18 13:02:11.516064 Intermediate result: Fidelity 0.99949378
2026-05-18 13:02:11.532861 Intermediate result: Fidelity 0.99951380
2026-05-18 13:02:11.546182 Intermediate result: Fidelity 0.99955313
2026-05-18 13:02:11.559168 Intermediate result: Fidelity 0.99955707
2026-05-18 13:02:11.571753 Intermediate result: Fidelity 0.99959306
2026-05-18 13:02:11.584257 Intermediate result: Fidelity 0.99960486
2026-05-18 13:02:11.597610 Intermediate result: Fidelity 0.99961714
2026-05-18 13:02:11.610106 Intermediate result: Fidelity 0.99962953
2026-05-18 13:02:11.622515 Intermediate result: Fidelity 0.99963525
2026-05-18 13:02:11.635543 Intermediate result: Fidelity 0.99964658
2026-05-18 13:02:11.649044 Intermediate result: Fidelity 0.99965027
2026-05-18 13:02:11.664148 Intermediate result: Fidelity 0.99965802
2026-05-18 13:02:11.678033 Intermediate result: Fidelity 0.99966731
2026-05-18 13:02:11.692714 Intermediate result: Fidelity 0.99967780
2026-05-18 13:02:11.706753 Intermediate result: Fidelity 0.99968567
2026-05-18 13:02:11.720780 Intermediate result: Fidelity 0.99969139
2026-05-18 13:02:11.733471 Intermediate result: Fidelity 0.99969628
2026-05-18 13:02:11.745998 Intermediate result: Fidelity 0.99970331
2026-05-18 13:02:11.758424 Intermediate result: Fidelity 0.99970796
2026-05-18 13:02:11.771986 Intermediate result: Fidelity 0.99971165
2026-05-18 13:02:11.785841 Intermediate result: Fidelity 0.99971892
2026-05-18 13:02:11.799105 Intermediate result: Fidelity 0.99972226
2026-05-18 13:02:11.811623 Intermediate result: Fidelity 0.99972441
2026-05-18 13:02:11.824114 Intermediate result: Fidelity 0.99972679
2026-05-18 13:02:11.837179 Intermediate result: Fidelity 0.99972965
2026-05-18 13:02:12.345479 Intermediate result: Fidelity 0.99972965
Done after 49 iterations.
<IBMBackend('ibm_pittsburgh')>
AQC circuit depth: 71
Baseline Trotter circuit depth: 111
Job ID: d85kc6o0bvlc73d5nhn0
# -------------------------Step 4-------------------------

hw_results = job.result()
aqc_expval = hw_results[0].data.evs.tolist()
baseline_expval = hw_results[1].data.evs.tolist()

print(f"Exact (MPS):        {exact_expval:.4f}")
print(
    f"Baseline Trotter:   {baseline_expval:.4f}, |\u0394| = {np.abs(exact_expval - baseline_expval):.4f}"
)
print(
    f"AQC (3+1):          {aqc_expval:.4f}, |\u0394| = {np.abs(exact_expval - aqc_expval):.4f}"
)

labels = [
    f"Baseline Trotter\n({baseline_num_trotter_steps} steps, depth {isa_baseline_circuit.depth(lambda x: x.operation.num_qubits == 2)})",
    f"AQC (3+1)\n(depth {isa_circuit.depth(lambda x: x.operation.num_qubits == 2)})",
]
values = [baseline_expval, aqc_expval]
colors = ["tab:orange", "tab:blue"]

plt.figure(figsize=(8, 5))
bars = plt.bar(labels, values, color=colors, width=0.5)
plt.axhline(
    y=exact_expval,
    color="tab:green",
    linestyle="--",
    linewidth=2,
    label=f"Exact ({exact_expval:.4f})",
)
plt.ylabel("Expected Value")
plt.title(
    "AQC-Tensor (3 compressed + 1 uncompressed) vs Baseline Trotter (50-site XXZ)"
)
plt.legend()
for bar in bars:
    y_val = bar.get_height()
    plt.text(
        bar.get_x() + bar.get_width() / 2.0,
        y_val,
        f"{y_val:.4f}",
        ha="center",
        va="bottom" if y_val >= 0 else "top",
    )
plt.axhline(y=0, color="black", linewidth=0.3)
plt.tight_layout()
plt.show()

Output:

Exact (MPS):        -0.7387
Baseline Trotter:   -0.5955, |Δ| = 0.1432
AQC (3+1):          -0.6734, |Δ| = 0.0653
Output of the previous code cell

다음 단계

권장사항

이 글이 흥미로웠다면, 다음 자료도 참고해 보시기 바랍니다:

이 페이지가 도움이 되었습니까?
GitHub에서 버그, 오타를 보고하거나 컨텐츠를 요청하십시오.