주기적 경계 조건을 위한 Circuit Cutting
사용량 예상: Eagle 프로세서에서 약 2분 (참고: 이 값은 추정치이며, 실제 실행 시간은 다를 수 있습니다.)
배경
이 노트북에서는 인접한 두 qubit 사이마다 2-Qubit 연산이 있는 주기적 qubit 체인의 시뮬레이션을 다룹니다. 여기에는 첫 번째와 마지막 qubit 간의 연산도 포함됩니다. 주기적 체인은 이징 모델(Ising model)이나 분자 시뮬레이션과 같은 물리학 및 화학 문제에서 자주 등장합니다.
현재 IBM Quantum® 장치는 평면 구조입니다. 일부 주기적 체인은 첫 번째와 마지막 Qubit이 서로 이웃하도록 토폴로지에 직접 배치할 수 있습니다. 그러나 문제 규모가 충분히 커지면 첫 번째와 마지막 Qubit이 서로 멀리 떨어지게 되어, 이 두 qubit 간의 2-Qubit 연산을 위해 많은 SWAP Gate가 필요해집니다. 이러한 주기적 경계 문제는 이 논문에서 연구된 바 있습니다.
이 노트북에서는 첫 번째와 마지막 Qubit이 이웃하지 않는 유틸리티 규모의 주기적 체인 문제를 처리하기 위해 Circuit cutting을 사용하는 방법을 보여줍니다. 이 장거리 연결을 잘라내면 여분의 SWAP Gate를 피할 수 있으며, 그 대신 Circuit의 여러 인스턴스를 실행하고 고전적인 후처리를 수행합니다. 요약하자면, Cutting을 통해 장거리 2-Qubit 연산을 논리적으로 계산할 수 있습니다. 다시 말해, 이 방법은 커플링 맵의 연결성을 효과적으로 높여 SWAP Gate의 수를 줄여줍니다.
Cutting에는 두 가지 유형이 있습니다. Circuit의 와이어를 자르는 방법(wire cutting)과 2-Qubit Gate를 여러 단일 qubit 연산으로 대체하는 방법(gate cutting)입니다. 이 노트북에서는 gate cutting에 집중합니다. gate cutting에 대한 자세한 내용은 qiskit-addon-cutting의 설명 자료와 해당 참고 문헌을 참조하세요. wire cutting에 대한 자세한 내용은 기댓값 추정을 위한 Wire Cutting 튜토리얼이나 qiskit-addon-cutting의 튜토리얼을 참조하세요.
요구 사항
이 튜토리얼을 시작하기 전에 다음이 설치되어 있는지 확인하세요:
- Qiskit SDK v1.2 이상 (
pip install qiskit) - Qiskit Runtime v0.3 이상 (
pip install qiskit-ibm-runtime) - Circuit cutting Qiskit addon v.9.0 이상 (
pip install qiskit-addon-cutting)
설정
# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy qiskit qiskit-addon-cutting qiskit-ibm-runtime
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
from qiskit.transpiler import PassManager
from qiskit.transpiler.passes import (
BasisTranslator,
Optimize1qGatesDecomposition,
)
from qiskit.circuit.equivalence_library import (
SessionEquivalenceLibrary as sel,
)
from qiskit.converters import circuit_to_dag, dag_to_circuit
from qiskit.result import sampled_expectation_value
from qiskit.quantum_info import SparsePauliOp
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit.circuit.library import TwoLocal
from qiskit_addon_cutting import (
cut_gates,
generate_cutting_experiments,
reconstruct_expectation_values,
)
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import SamplerV2, SamplerOptions, Batch
1단계: 고전적 입력을 양자 문제로 매핑하기
여기서는 TwoLocal Circuit을 생성하고 일부 관측량(observable)을 정의합니다.
- 입력: Circuit을 생성하기 위한 파라미터
- 출력: 추상 Circuit 및 관측량
entangler map의 마지막 Qubit과 첫 번째 Qubit 사이에 주기적 연결이 있는 하드웨어 효율적인 entangler map을 TwoLocal Circuit에 사용합니다. 이 장거리 상호작용은 트랜스파일 과정에서 여분의 SWAP Gate를 유발할 수 있어 Circuit 깊이가 증가합니다.
Backend 및 초기 레이아웃 선택
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=127
)
이 노트북에서는 127-Qubit IBM Quantum 장치의 토폴로지에서 가장 긴 1D 체인인 109-Qubit 주기적 1D 체인을 고려합니다. 여분의 SWAP Gate 없이 첫 번째와 마지막 Qubit이 이웃하도록 109-Qubit 주기적 체인을 127-Qubit 장치에 배치하는 것은 불가능합니다.
init_layout = [
13,
12,
11,
10,
9,
8,
7,
6,
5,
4,
3,
2,
1,
0,
14,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
32,
36,
51,
50,
49,
48,
47,
46,
45,
44,
43,
42,
41,
40,
39,
38,
37,
52,
56,
57,
58,
59,
60,
61,
62,
63,
64,
65,
66,
67,
68,
69,
70,
74,
89,
88,
87,
86,
85,
84,
83,
82,
81,
80,
79,
78,
77,
76,
75,
90,
94,
95,
96,
97,
98,
99,
100,
101,
102,
103,
104,
105,
106,
107,
108,
112,
126,
125,
124,
123,
122,
121,
120,
119,
118,
117,
116,
115,
114,
113,
]
# the number of qubits in the circuit is governed by the length of the initial layout
num_qubits = len(init_layout)
num_qubits
109
TwoLocal Circuit을 위한 entangler map 구성
coupling_map = [(i, i + 1) for i in range(0, len(init_layout) - 1)]
coupling_map.append(
(len(init_layout) - 1, 0)
) # adding in the periodic connectivity
TwoLocal Circuit은 rotation_blocks와 entangler map을 여러 번 반복할 수 있습니다. 이 경우 반복 횟수에 따라 잘라야 할 주기적 Gate의 수가 결정됩니다. 샘플링 오버헤드는 Cut 수에 따라 지수적으로 증가하므로 (자세한 내용은 기댓값 추정을 위한 Wire Cutting 튜토리얼을 참조), 이 노트북에서는 반복 횟수를 2로 고정합니다.
num_reps = 2
entangler_map = []
for even_edge in coupling_map[0 : len(coupling_map) : 2]:
entangler_map.append(even_edge)
for odd_edge in coupling_map[1 : len(coupling_map) : 2]:
entangler_map.append(odd_edge)
ansatz = TwoLocal(
num_qubits=num_qubits,
rotation_blocks="rx",
entanglement_blocks="cx",
entanglement=entangler_map,
reps=num_reps,
).decompose()
ansatz.draw("mpl", fold=-1)

Circuit cutting의 결과 품질을 검증하려면 이상적인 결과를 알아야 합니다. 현재 선택한 Circuit은 무차별 대입 고전 시뮬레이션의 범위를 넘어섭니다. 따라서 Circuit이 클리포드(Clifford)가 되도록 파라미터를 신중하게 고정합니다.
첫 두 레이어의 Rx Gate에는 파라미터 값 을, 마지막 레이어에는 를 할당합니다. 이를 통해 이 Circuit의 이상적인 결과가 (은 Qubit 수)이 됩니다. 따라서 Qubit 인덱스가 일 때, 의 기댓값은 이고, 의 기댓값은 입니다.
params_last_layer = [np.pi] * ansatz.num_qubits
params = [0] * (ansatz.num_parameters - ansatz.num_qubits)
params.extend(params_last_layer)
ansatz.assign_parameters(params, inplace=True)
관측량 선택
Gate cutting의 이점을 수량화하기 위해 관측량 및 의 기댓값을 측정합니다. 앞서 언급했듯이, 이상적인 기댓값은 각각 과 입니다.
observables = []
for i in range(num_qubits):
obs = "I" * (i) + "Z" + "I" * (num_qubits - i - 1)
observables.append(obs)
for i in range(num_qubits):
if i == num_qubits - 1:
obs = "Z" + "I" * (num_qubits - 2) + "Z"
else:
obs = "I" * i + "ZZ" + "I" * (num_qubits - i - 2)
observables.append(obs)
observables = SparsePauliOp(observables)
paulis = observables.paulis
coeffs = observables.coeffs
Step 2: 양자 하드웨어 실행을 위한 문제 최적화
- 입력: 추상 Circuit과 관측값
- 출력: 장거리 Gate를 절단하여 생성된 대상 Circuit과 관측값
Circuit 트랜스파일
Circuit은 이 단계에서 트랜스파일하거나, 절단 이후에 트랜스파일할 수 있습니다. 절단 이후에 트랜스파일하면 샘플링 오버헤드로 인해 생성된 각 부분 실험(subexperiment)마다 별도로 트랜스파일해야 합니다. 따라서 트랜스파일 오버헤드를 줄이려면 이 단계에서 트랜스파일하는 것이 더 현명합니다.
그러나 이 단계에서 실제 하드웨어 연결성을 기준으로 트랜스파일하면, Transpiler가 주기적인 2-Qubit 연산을 배치하기 위해 여러 개의 SWAP Gate를 삽입하게 되어 Circuit 절단의 이점이 가려집니다. 이 문제를 피하기 위해, 어떤 Gate를 절단해야 하는지 정확히 알고 있다는 사실을 활용할 수 있습니다. 구체적으로, 멀리 떨어진 Qubit 간에 가상 연결을 추가하여 이 주기적인 2-Qubit Gate를 수용하는 가상 커플링 맵(virtual coupling map)을 만들 수 있습니다. 이렇게 하면 추가 SWAP Gate 없이 이 단계에서 Circuit을 트랜스파일할 수 있습니다.
coupling_map = backend.configuration().coupling_map
# create a virtual coupling map with long range connectivity
virtual_coupling_map = coupling_map.copy()
virtual_coupling_map.append([init_layout[-1], init_layout[0]])
virtual_coupling_map.append([init_layout[0], init_layout[-1]])
pm_virtual = generate_preset_pass_manager(
optimization_level=1,
coupling_map=virtual_coupling_map,
initial_layout=init_layout,
basis_gates=backend.configuration().basis_gates,
)
virtual_mapped_circuit = pm_virtual.run(ansatz)
virtual_mapped_circuit.draw("mpl", fold=-1, idle_wires=False)

장거리 주기 연결성 절단
이제 트랜스파일된 Circuit에서 Gate를 절단합니다. 절단해야 할 2-Qubit Gate는 레이아웃의 첫 번째와 마지막 Qubit을 연결하는 Gate임을 유의하세요.
# Find the indices of the distant gates
cut_indices = [
i
for i, instruction in enumerate(virtual_mapped_circuit.data)
if {virtual_mapped_circuit.find_bit(q)[0] for q in instruction.qubits}
== {init_layout[-1], init_layout[0]}
]
트랜스파일된 Circuit의 레이아웃을 관측값에 적용합니다.
trans_observables = observables.apply_layout(virtual_mapped_circuit.layout)
마지막으로, 서로 다른 측정 및 준비 기저(basis)를 샘플링하여 부분 실험이 생성됩니다.
qpd_circuit, bases = cut_gates(virtual_mapped_circuit, cut_indices)
subexperiments, coefficients = generate_cutting_experiments(
circuits=qpd_circuit,
observables=trans_observables.paulis,
num_samples=np.inf,
)
장거리 상호작용을 절단하면 측정 및 준비 기저가 서로 다른 여러 Circuit 샘플이 실행됩니다. 이에 대한 자세한 내용은 Constructing a virtual two-qubit gate by sampling single-qubit operations 및 Cutting circuits with multiple two-qubit unitaries를 참고하세요.
절단해야 할 주기적 Gate의 수는 위에서 num_reps로 정의한 TwoLocal 레이어의 반복 횟수와 같습니다. Gate 절단의 샘플링 오버헤드는 6이므로, 부분 실험의 총 수는 가 됩니다.
print(f"Number of subexperiments is {len(subexperiments)} = 6**{num_reps}")
Number of subexperiments is 36 = 6**2
부분 실험 트랜스파일
현재 부분 실험에는 기저 Gate 집합에 속하지 않는 일부 1-Qubit Gate가 포함된 Circuit이 있습니다. 절단된 Qubit은 서로 다른 기저에서 측정되며, 이를 위해 사용되는 회전 Gate가 반드시 기저 Gate 집합에 속하지 않기 때문입니다. 예를 들어, X 기저에서의 측정은 일반적인 Z 기저 측정 전에 Hadamard Gate를 적용하는 것을 의미하지만, Hadamard는 기저 Gate 집합의 일부가 아닙니다.
부분 실험의 각 Circuit에 전체 트랜스파일 과정을 적용하는 대신, 특정 트랜스파일 패스를 사용할 수 있습니다. 사용 가능한 모든 트랜스파일 패스에 대한 자세한 설명은 이 문서를 참고하세요.
pass_ = PassManager(
[Optimize1qGatesDecomposition(basis=backend.configuration().basis_gates)]
)
subexperiments = pass_.run(
[
dag_to_circuit(
BasisTranslator(sel, target_basis=backend.basis_gates).run(
circuit_to_dag(circ)
)
)
for circ in subexperiments
]
)
Step 3: Qiskit 기본 요소를 사용한 실행
- 입력: 대상 Circuit
- 출력: 준확률 분포(Quasi-probability distributions)
절단된 Circuit 실행에는 SamplerV2 기본 요소를 사용합니다. 이 유형의 Circuit에서 Gate 절단의 효과적인 적용으로 인한 개선만을 확인하기 위해, dynamical decoupling과 twirling을 비활성화합니다.
options = SamplerOptions()
options.default_shots = 10000
options.dynamical_decoupling.enable = False
options.twirling.enable_gates = False
options.twirling.enable_measure = False
이제 배치(batch) 모드를 사용하여 작업을 제출합니다.
with Batch(backend=backend) as batch:
sampler = SamplerV2(options=options)
cut_job = sampler.run(subexperiments)
print(f"Job ID {cut_job.job_id()}")
Job ID cwxf7wq60bqg008pvt8g
result = cut_job.result()
Step 4: 후처리 및 원하는 고전적 형식으로 결과 반환
- 입력: 준확률 분포
- 출력: 재구성된 기댓값
reconstructed_expvals = reconstruct_expectation_values(
result,
coefficients,
paulis,
)
이제 가중치-1 및 가중치-2 Z형 관측값의 평균을 계산합니다.
cut_weight_1 = np.mean(reconstructed_expvals[:num_qubits])
cut_weight_2 = np.mean(reconstructed_expvals[num_qubits:])
print(f"Average of weight-1 expectation values is {cut_weight_1}")
print(f"Average of weight-2 expectation values is {cut_weight_2}")
Average of weight-1 expectation values is -0.741733944954063
Average of weight-2 expectation values is 0.6968862385320495
교차 검증: 절단하지 않은 기댓값 구하기
절단하지 않은 경우와 비교하여 Circuit 절단 기법의 이점을 교차 검증하는 것이 유용합니다. 여기서는 Circuit을 절단하지 않고 기댓값을 계산합니다. 절단되지 않은 이런 Circuit은 첫 번째와 마지막 Qubit 간의 2-Qubit 연산을 구현하기 위해 많은 수의 SWAP Gate가 필요합니다. SamplerV2를 통해 확률 분포를 얻은 후, sampled_expectation_value 함수를 사용하여 절단되지 않은 Circuit의 기댓값을 구합니다. 이를 통해 모든 인스턴스에서 기본 요소를 균일하게 사용할 수 있습니다. 다만, 기댓값을 직접 계산하기 위해 EstimatorV2를 사용하는 것도 가능합니다.
if ansatz.num_clbits == 0:
ansatz.measure_all()
pm_uncut = generate_preset_pass_manager(
optimization_level=1, backend=backend, initial_layout=init_layout
)
transpiled_circuit = pm_uncut.run(ansatz)
sampler = SamplerV2(mode=backend, options=options)
uncut_job = sampler.run([transpiled_circuit])
uncut_job_id = uncut_job.job_id()
print(f"The job id for the uncut clifford circuit is {uncut_job_id}")
The job id for the uncut clifford circuit is cwxfads2ac5g008jhe7g
uncut_result = uncut_job.result()[0]
uncut_counts = uncut_result.data.meas.get_counts()
이제 절단하지 않은 경우의 모든 가중치-1 및 가중치-2 Z형 관측값의 평균 기댓값을 계산합니다.
uncut_expvals = [
sampled_expectation_value(uncut_counts, obs) for obs in paulis
]
uncut_weight_1 = np.mean(uncut_expvals[:num_qubits])
uncut_weight_2 = np.mean(uncut_expvals[num_qubits:])
print(f"Average of weight-1 expectation values is {uncut_weight_1}")
print(f"Average of weight-2 expectation values is {uncut_weight_2}")
Average of weight-1 expectation values is -0.32494128440366965
Average of weight-2 expectation values is 0.32340917431192656
시각화
주기적 체인 Circuit에 Gate 절단을 사용했을 때 가중치-1 및 가중치-2 관측값에서 얻은 개선 결과를 시각화해 보겠습니다.
mpl.rcParams.update(mpl.rcParamsDefault)
fig = plt.subplots(figsize=(12, 8), dpi=200)
width = 0.25
labels = ["Weight-1", "Weight-2"]
x = np.arange(len(labels))
ideal = [-1, 1]
cut = [cut_weight_1, cut_weight_2]
uncut = [uncut_weight_1, uncut_weight_2]
br1 = np.arange(len(ideal))
br2 = [x + width for x in br1]
br3 = [x + width for x in br2]
plt.bar(
br1, ideal, width=width, edgecolor="k", label="Ideal", color="#4589ff"
)
plt.bar(br2, cut, width=width, edgecolor="k", label="Cut", color="#a56eff")
plt.bar(
br3, uncut, width=width, edgecolor="k", label="Uncut", color="#009d9a"
)
plt.axhline(y=0, color="k", linestyle="-")
plt.xticks([r + width for r in range(len(ideal))], labels, fontsize=14)
plt.yticks(fontsize=14)
plt.legend(fontsize=14)
plt.show()

요약
요약하자면, 109개의 Qubit으로 이루어진 주기적 1D 체인에서 가중치-1 및 가중치-2 Z형 관측값의 평균 기댓값을 계산했습니다. 이를 위해 다음과 같은 작업을 수행했습니다.
- 1D 체인의 첫 번째와 마지막 Qubit 간에 장거리 연결을 추가한 가상 커플링 맵을 만들고 Circuit을 트랜스파일했습니다.
- 이 단계에서 트랜스파일함으로써 절단 후 각 부분 실험을 별도로 트랜스파일하는 오버헤드를 피할 수 있었으며,
- 가상 커플링 맵을 사용하여 첫 번째와 마지막 Qubit 간의 2-Qubit 연산에 필요한 추가 SWAP Gate를 피할 수 있었습니다.
- Gate 절단을 통해 트랜스파일된 Circuit에서 장거리 연결을 제거했습니다.
- 적절한 트랜스파일 패스를 적용하여 절단된 Circuit을 기저 Gate 집합으로 변환했습니다.
SamplerV2기본 요소를 사용하여 IBM Quantum 장치에서 절단된 Circuit을 실행했습니다.- 절단된 Circuit의 결과를 재구성하여 기댓값을 얻었습니다.
결론
결과를 보면, Gate 절단을 통해 가중치-1 및 가중치-2 형 관측값의 평균이 주기적 Gate를 절단했을 때 크게 향상되었음을 알 수 있습니다. 이 연구에는 오류 억제 또는 완화 기법이 포함되지 않았음을 유의하세요. 관찰된 개선은 오직 이 문제에 대한 Gate 절단의 적절한 적용 덕분입니다. 완화 및 억제 기법을 함께 사용하면 결과를 더욱 향상시킬 수 있었을 것입니다.
이 연구는 Gate 절단을 효과적으로 활용하여 계산 성능을 향상시키는 예시를 보여줍니다.
튜토리얼 설문조사
이 짧은 설문조사를 통해 이 튜토리얼에 대한 피드백을 제공해 주세요. 여러분의 의견은 콘텐츠와 사용자 경험을 개선하는 데 도움이 됩니다.
Note: This survey is provided by IBM Quantum and relates to the original English content. To give feedback on doQumentation's website, translations, or code execution, please open a GitHub issue.