주 콘텐츠로 건너뛰기

니시모리 상전이

사용 시간 예상: Heron r2 프로세서 기준 3분 (참고: 이는 예상치이며, 실제 실행 시간은 다를 수 있습니다.)

배경

이 튜토리얼은 IBM® 양자 프로세서에서 니시모리 상전이를 구현하는 방법을 설명합니다. 이 실험은 원래 Realizing the Nishimori transition across the error threshold for constant-depth quantum circuits에서 소개되었습니다.

니시모리 상전이는 랜덤 결합 이징 모델에서 단범위 질서 위상과 장범위 질서 위상 간의 전이를 말합니다. 양자 컴퓨터에서 장범위 질서 위상은 전체 장치에 걸쳐 Qubit들이 얽힌 상태로 나타납니다. 이 고도로 얽힌 상태는 측정에 의한 얽힘 생성 (GEM) 프로토콜을 사용하여 준비됩니다. 중간 Circuit 측정을 활용함으로써 GEM 프로토콜은 일정 깊이의 Circuit만으로도 전체 장치에 걸쳐 Qubit들을 얽을 수 있습니다. 이 튜토리얼은 GEM Suite 소프트웨어 패키지의 GEM 프로토콜 구현을 사용합니다.

요구 사항

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

  • Qiskit SDK v1.0 이상 (시각화 지원 포함)
  • Qiskit Runtime v0.22 이상 ( pip install qiskit-ibm-runtime )
  • GEM Suite ( pip install gem-suite )

설정

# Added by doQumentation — required packages for this notebook
!pip install -q gem-suite matplotlib qiskit qiskit-ibm-runtime
import matplotlib.pyplot as plt

from collections import defaultdict

from qiskit_ibm_runtime import QiskitRuntimeService

from qiskit.transpiler import generate_preset_pass_manager

from gem_suite import PlaquetteLattice
from gem_suite.experiments import GemExperiment

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

GEM 프로토콜은 격자로 설명되는 Qubit 연결성을 가진 양자 프로세서에서 작동합니다. 오늘날의 IBM 양자 프로세서는 heavy hex 격자를 사용합니다. 프로세서의 Qubit들은 차지하는 격자의 단위 셀에 따라 플래킷으로 그룹화됩니다. Qubit이 두 개 이상의 단위 셀에 속할 수 있으므로, 플래킷들은 서로 분리되어 있지 않습니다. Heavy hex 격자에서 플래킷은 12개의 Qubit을 포함합니다. 플래킷 자체도 격자를 형성하며, 두 플래킷이 Qubit을 공유하면 연결됩니다. Heavy hex 격자에서 인접한 플래킷은 3개의 Qubit을 공유합니다.

GEM Suite 소프트웨어 패키지에서 GEM 프로토콜을 구현하는 기본 클래스는 PlaquetteLattice이며, 이는 플래킷의 격자(heavy hex 격자와는 다릅니다)를 나타냅니다. PlaquetteLattice는 Qubit 결합 맵으로부터 초기화할 수 있습니다. 현재는 heavy hex 결합 맵만 지원됩니다.

다음 코드 셀은 IBM 양자 프로세서의 결합 맵에서 플래킷 격자를 초기화합니다. 플래킷 격자가 항상 전체 하드웨어를 포함하지는 않습니다. 예를 들어, ibm_torino는 총 133개의 Qubit을 가지지만, 장치에 맞는 가장 큰 플래킷 격자는 그 중 125개만 사용하며 총 18개의 플래킷으로 구성됩니다. 다른 Qubit 수를 가진 IBM Quantum® 장치에서도 유사한 현상이 관찰됩니다.

# QiskitRuntimeService.save_account(channel="ibm_quantum", token="<YOUR_API_KEYN>", overwrite=True, set_as_default=True)
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=127
)
plaquette_lattice = PlaquetteLattice.from_coupling_map(backend.coupling_map)

print(f"Number of qubits in backend: {backend.num_qubits}")
print(
f"Number of qubits in plaquette lattice: {len(list(plaquette_lattice.qubits()))}"
)
print(f"Number of plaquettes: {len(list(plaquette_lattice.plaquettes()))}")
Number of qubits in backend: 133
Number of qubits in plaquette lattice: 125
Number of plaquettes: 18

플래킷 격자의 그래프 표현 다이어그램을 생성하여 시각화할 수 있습니다. 다이어그램에서 플래킷은 레이블이 붙은 육각형으로 표현되며, 두 플래킷이 Qubit을 공유하면 간선으로 연결됩니다.

plaquette_lattice.draw_plaquettes()

Output of the previous code cell

plaquettes 메서드를 사용하여 개별 플래킷이 포함하는 Qubit 등의 정보를 조회할 수 있습니다.

# Get a list of the plaquettes
plaquettes = list(plaquette_lattice.plaquettes())
# Display information about plaquette 0
plaquettes[0]
PyPlaquette(index=0, qubits=[0, 1, 2, 3, 4, 15, 16, 19, 20, 21, 22, 23], neighbors=[3, 1])

플래킷 격자를 구성하는 기본 Qubit의 다이어그램도 생성할 수 있습니다.

plaquette_lattice.draw_qubits()

Output of the previous code cell

Qubit 레이블과 연결된 Qubit을 나타내는 간선 외에도, 다이어그램에는 GEM 프로토콜과 관련된 세 가지 추가 정보가 포함됩니다:

  • 각 Qubit은 음영 처리(회색)되거나 음영 없음으로 표시됩니다. 음영 처리된 Qubit은 이징 모델의 사이트를 나타내는 "사이트" Qubit이며, 음영 없는 Qubit은 사이트 Qubit 간의 상호 작용을 매개하는 "결합" Qubit입니다.
  • 각 사이트 Qubit은 (A) 또는 (B)로 레이블이 지정되어 GEM 프로토콜에서 사이트 Qubit이 수행할 수 있는 두 가지 역할 중 하나를 나타냅니다 (역할은 나중에 설명됩니다).
  • 각 간선은 여섯 가지 색상 중 하나로 색칠되어 간선을 여섯 그룹으로 분할합니다. 이 분할은 2-Qubit Gate를 병렬화하는 방법과 노이즈가 있는 양자 프로세서에서 다른 양의 오류를 유발할 가능성이 있는 다양한 스케줄링 패턴을 결정합니다. 그룹 내 간선은 서로 분리되어 있으므로, 해당 간선에 대해 2-Qubit Gate 레이어를 동시에 적용할 수 있습니다. 실제로, 여섯 가지 색상을 두 색상씩 세 그룹으로 나누어 각 두 색상의 합집합이 여전히 분리되도록 할 수 있습니다. 따라서 모든 간선을 활성화하는 데 단 세 레이어의 2-Qubit Gate만 필요합니다. 여섯 색상을 이렇게 분할하는 방법은 12가지가 있으며, 각 분할은 서로 다른 3-레이어 Gate 스케줄을 생성합니다.

플래킷 격자를 생성했다면, 다음 단계는 플래킷 격자와 실험을 실행할 Backend를 모두 전달하여 GemExperiment 객체를 초기화하는 것입니다. GemExperiment 클래스는 Circuit 생성, 작업 제출, 데이터 분석을 포함한 GEM 프로토콜의 실제 구현을 관리합니다. 다음 코드 셀은 플래킷 격자를 두 개의 플래킷(21개의 Qubit)으로만 제한하여 실험 클래스를 초기화함으로써, 하드웨어의 노이즈가 신호를 압도하지 않도록 실험 규모를 줄입니다.

gem_exp = GemExperiment(plaquette_lattice.filter([9, 12]), backend=backend)

# visualize the plaquette lattice after filtering
plaquette_lattice.filter([9, 12]).draw_qubits()

Output of the previous code cell

GEM 프로토콜 Circuit은 다음 단계로 구성됩니다:

  1. 모든 Qubit에 Hadamard Gate를 적용하여 전체 +|+\rangle 상태를 준비합니다.
  2. 연결된 모든 Qubit 쌍에 RZZR_{ZZ} Gate를 적용합니다. 이는 3개의 Gate 레이어를 사용하여 달성할 수 있습니다. 각 RZZR_{ZZ} Gate는 사이트 Qubit과 결합 Qubit에 작용합니다. 사이트 Qubit이 (B)로 레이블된 경우, 각도는 π2\frac{\pi}{2}로 고정됩니다. 사이트 Qubit이 (A)로 레이블된 경우, 각도는 다양한 Circuit을 생성하도록 변경될 수 있습니다. 기본적으로 각도 범위는 00부터 π2\frac{\pi}{2}까지 포함하여 21개의 등간격 점으로 설정됩니다.
  3. 각 결합 Qubit을 파울리 XX 기저에서 측정합니다. Qubit은 파울리 ZZ 기저에서 측정되므로, Qubit을 측정하기 전에 Hadamard Gate를 적용하면 됩니다.

이 튜토리얼의 소개에서 인용된 논문은 RZZR_{ZZ} 각도에 대해 다른 관례를 사용하며, 이 튜토리얼에서 사용하는 관례와 2배 차이가 납니다.

3단계에서는 결합 Qubit만 측정됩니다. 사이트 Qubit이 남아 있는 상태를 이해하기 위해, 2단계에서 사이트 Qubit (A)에 적용된 RZZR_{ZZ} 각도가 π2\frac{\pi}{2}와 같은 경우를 고려하는 것이 유용합니다. 이 경우, 사이트 Qubit은 GHZ 상태와 유사한 고도로 얽힌 상태에 남게 됩니다,

GHZ=0000+1111.\lvert \text{GHZ} \rangle = \lvert 00 \cdots 00 \rangle + \lvert 11 \cdots 11 \rangle.

측정 결과의 무작위성으로 인해 사이트 Qubit의 실제 상태는 장범위 질서를 가진 다른 상태일 수 있습니다. 예를 들어, 00110+11001\lvert 00110 \rangle + \lvert 11001 \rangle. 그러나 측정 결과를 기반으로 한 디코딩 연산을 적용하면 GHZ 상태를 복원할 수 있습니다. RZZR_{ZZ} 각도를 π2\frac{\pi}{2}에서 낮추면, 노이즈가 없는 경우 약 0.3π0.3 \pi의 임계 각도까지 장범위 질서를 복원할 수 있습니다. 이 각도 아래에서는 결과 상태가 더 이상 장범위 얽힘을 나타내지 않습니다. 이 장범위 질서의 존재와 부재 사이의 전이가 니시모리 상전이입니다.

위의 설명에서 사이트 Qubit은 측정되지 않았으며, 양자 Gate를 적용하여 디코딩 연산을 수행할 수 있습니다. GEM 스위트에서 구현된 실험(이 튜토리얼이 따르는)에서는 사이트 Qubit이 실제로 측정되며, 디코딩 연산은 고전적 후처리 단계에서 적용됩니다.

위의 설명에서 디코딩 연산은 양자 상태를 복원하기 위해 사이트 Qubit에 양자 Gate를 적용하여 수행할 수 있습니다. 그러나 목표가 예를 들어 특성화 목적으로 상태를 즉시 측정하는 것이라면, 사이트 Qubit은 결합 Qubit과 함께 측정되며 디코딩 연산은 고전적 후처리 단계에서 적용될 수 있습니다. 이것이 이 튜토리얼이 따르는 GEM 스위트에서 실험이 구현되는 방식입니다.

2단계에서 RZZR_{ZZ} 각도(기본값으로 21개의 값을 스윕)에 따라 달라지는 것 외에도, GEM 프로토콜 Circuit은 3개의 RZZR_{ZZ} Gate 레이어를 구현하는 데 사용되는 스케줄링 패턴에도 달라집니다. 앞서 논의한 바와 같이, 이러한 스케줄링 패턴은 12가지입니다. 따라서 실험의 총 Circuit 수는 21×12=25221 \times 12 = 252입니다.

실험의 Circuit은 GemExperiment 클래스의 circuits 메서드를 사용하여 생성할 수 있습니다.

circuits = gem_exp.circuits()
print(f"Total number of circuits: {len(circuits)}")
Total number of circuits: 252

이 튜토리얼의 목적상, 단일 스케줄링 패턴만 고려하면 충분합니다. 다음 코드 셀은 실험을 첫 번째 스케줄링 패턴으로 제한합니다. 결과적으로, 실험에는 스윕되는 각 RZZR_{ZZ} 각도에 대해 하나씩, 총 21개의 Circuit만 포함됩니다.

# Restrict experiment to the first scheduling pattern
gem_exp.set_experiment_options(schedule_idx=0)

# There are less circuits now
circuits = gem_exp.circuits()
print(f"Total number of circuits: {len(circuits)}")

# Print the RZZ angles swept over
print(f"RZZ angles:\n{gem_exp.parameters()}")
Total number of circuits: 21
RZZ angles:
[0. 0.07853982 0.15707963 0.23561945 0.31415927 0.39269908
0.4712389 0.54977871 0.62831853 0.70685835 0.78539816 0.86393798
0.9424778 1.02101761 1.09955743 1.17809725 1.25663706 1.33517688
1.41371669 1.49225651 1.57079633]

다음 코드 셀은 인덱스 5의 Circuit 다이어그램을 그립니다. 다이어그램 크기를 줄이기 위해 Circuit 끝의 측정 Gate를 제거합니다.

# Get the circuit at index 5
circuit = circuits[5]
# Remove the final measurements to ease visualization
circuit.remove_final_measurements()
# Draw the circuit
circuit.draw("mpl", fold=-1, scale=0.5)

Output of the previous code cell

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

하드웨어 실행을 위한 양자 Circuit Transpiling은 일반적으로 여러 단계를 포함합니다. 일반적으로 가장 많은 계산 비용이 드는 단계는 Qubit 레이아웃 선택, 하드웨어의 Qubit 연결성에 맞게 2-Qubit Gate를 라우팅하는 것, 그리고 Gate 수와 깊이를 최소화하기 위해 Circuit을 최적화하는 것입니다. GEM 프로토콜에서는 하드웨어 연결성이 이미 프로토콜 설계에 통합되어 있으므로 레이아웃 및 라우팅 단계가 불필요합니다. Circuit에는 이미 Qubit 레이아웃이 있으며, 2-Qubit Gate는 이미 기본 연결에 매핑되어 있습니다. 또한, RZZR_{ZZ} 각도가 변경될 때 Circuit의 구조를 보존하기 위해 매우 기본적인 Circuit 최적화만 수행해야 합니다.

GemExperiment 클래스는 실험을 실행할 때 Circuit을 투명하게 Transpiling합니다. 레이아웃 및 라우팅 단계는 기본적으로 아무것도 하지 않도록 이미 재정의되어 있으며, Circuit 최적화는 단일 Qubit Gate만 최적화하는 수준에서 수행됩니다. 그러나 set_transpile_options 메서드를 사용하여 추가 옵션을 재정의하거나 전달할 수 있습니다. 시각화를 위해, 다음 코드 셀은 이전에 표시된 Circuit을 수동으로 Transpiling하고 Transpiling된 Circuit을 그립니다.

# Demonstrate setting transpile options
gem_exp.set_transpile_options(
optimization_level=1 # This is the default optimization level
)
pass_manager = generate_preset_pass_manager(
backend=backend,
initial_layout=list(gem_exp.physical_qubits),
**dict(gem_exp.transpile_options),
)
transpiled = pass_manager.run(circuit)
transpiled.draw("mpl", idle_wires=False, fold=-1, scale=0.5)

Output of the previous code cell

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

하드웨어에서 GEM 프로토콜 Circuit을 실행하려면, GemExperiment 객체의 run 메서드를 호출하세요. 각 Circuit에서 샘플링할 샷 수를 지정할 수 있습니다. run 메서드는 ExperimentData 객체를 반환하며 변수에 저장해야 합니다. run 메서드는 작업이 완료되기를 기다리지 않고 작업만 제출하므로 비차단 호출입니다.

exp_data = gem_exp.run(shots=10_000)

결과를 기다리려면, ExperimentData 객체의 block_for_results 메서드를 호출하세요. 이 호출은 작업이 완료될 때까지 인터프리터를 중단시킵니다.

exp_data.block_for_results()
ExperimentData(GemExperiment, d0d5880a-34c1-4aab-a7b6-c4f58516bc03, job_ids=['cwg12ptmptp00082khhg'], metadata=<5 items>, figure_names=['two_point_correlation.svg', 'normalized_variance.svg', 'plaquette_ops.svg', 'bond_ops.svg'])

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

RZZR_{ZZ} 각도가 π2\frac{\pi}{2}일 때, 노이즈가 없다면 디코딩된 상태는 GHZ 상태가 됩니다. GHZ 상태의 장범위 질서는 측정된 비트 문자열의 자화를 플롯하여 시각화할 수 있습니다. 자화 MM은 단일 Qubit 파울리 ZZ 연산자의 합으로 정의됩니다,

M=j=1NZj,M = \sum_{j=1}^N Z_j,

여기서 NN은 사이트 Qubit의 수입니다. 비트 문자열에 대한 값은 0의 개수와 1의 개수의 차이와 같습니다. GHZ 상태를 측정하면 모두 0인 상태 또는 모두 1인 상태가 동일한 확률로 나오므로, 자화는 절반의 확률로 +N+N이 되고 나머지 절반은 N-N이 됩니다. 노이즈로 인한 오류가 있는 경우 다른 값도 나타나지만, 노이즈가 너무 크지 않으면 분포는 여전히 +N+NN-N 근처에서 피크를 보입니다.

디코딩 전 원시 비트 문자열의 경우, 자화 분포는 노이즈가 없을 때 균일한 무작위 비트 문자열의 분포와 동일합니다.

다음 코드 셀은 RZZR_{ZZ} 각도가 π2\frac{\pi}{2}일 때 원시 비트 문자열과 디코딩된 비트 문자열의 자화를 플롯합니다.

def magnetization_distribution(
counts_dict: dict[str, int],
) -> dict[str, float]:
"""Compute magnetization distribution from counts dictionary."""
# Construct dictionary from magnetization to count
mag_dist = defaultdict(float)
for bitstring, count in counts_dict.items():
mag = bitstring.count("0") - bitstring.count("1")
mag_dist[mag] += count
# Normalize
shots = sum(counts_dict.values())
for mag in mag_dist:
mag_dist[mag] /= shots
return mag_dist

# Get counts dictionaries with and without decoding
data = exp_data.data()
# Get the last data point, which is at the angle for the GHZ state
raw_counts = data[-1]["counts"]
# Without decoding
site_indices = [
i for i, q in enumerate(gem_exp.plaquettes.qubits()) if q.role == "Site"
]
site_raw_counts = defaultdict(int)
for key, val in raw_counts.items():
site_str = "".join(key[-1 - i] for i in site_indices)
site_raw_counts[site_str] += val
# With decoding
_, site_decoded_counts = gem_exp.plaquettes.decode_outcomes(
raw_counts, return_counts=True
)

# Compute magnetization distribution
raw_magnetization = magnetization_distribution(site_raw_counts)
decoded_magnetization = magnetization_distribution(site_decoded_counts)

# Plot
plt.bar(*zip(*raw_magnetization.items()), label="raw")
plt.bar(*zip(*decoded_magnetization.items()), label="decoded", width=0.3)
plt.legend()
plt.xlabel("Magnetization")
plt.ylabel("Frequency")
plt.title("Magnetization distribution with and without decoding")
Text(0.5, 1.0, 'Magnetization distribution with and without decoding')

Output of the previous code cell

장범위 질서를 더 엄밀하게 특성화하려면, 다음과 같이 정의된 평균 이점 상관 ff를 살펴볼 수 있습니다,

f=1N2(M2M2).f = \frac{1}{N^2} \left(\langle M^2 \rangle - \langle M \rangle ^2\right).

값이 높을수록 더 높은 수준의 얽힘을 나타냅니다. GemExperiment 클래스는 실험 데이터 처리의 일부로 디코딩된 비트 문자열에 대해 이 값을 자동으로 계산합니다. 실험 데이터 클래스의 figure 메서드를 통해 접근 가능한 그림을 저장합니다. 이 경우 그림의 이름은 two_point_correlation입니다.

exp_data.figure("two_point_correlation")

Output of the previous code cell

니시모리 상전이의 임계점을 결정하려면, 다음과 같이 정의된 M2/NM^2 / N의 정규화된 분산을 살펴볼 수 있습니다,

g=1N3(M4M22),g = \frac{1}{N^3} \left(\langle M^4 \rangle - \langle M^2 \rangle^2\right),

이는 제곱 자화의 변동량을 정량화합니다. 이 값은 니시모리 상전이의 임계점에서 최대가 됩니다. 노이즈가 없는 경우, 임계점은 약 0.3π0.3 \pi에서 발생합니다. 노이즈가 있는 경우, 임계점은 더 높은 쪽으로 이동하지만, 임계점이 0.5π0.5 \pi 이하에서 발생하는 한 상전이는 여전히 관찰됩니다.

exp_data.figure("normalized_variance")

Output of the previous code cell

실험 확장

다음 코드 셀은 6개의 플래킷(49개의 Qubit)과 전체 12개의 플래킷(125개의 Qubit)에 대해 실험을 실행하고 정규화된 분산을 플롯합니다. 실험이 더 큰 크기로 확장될수록, 더 많은 노이즈가 임계점을 오른쪽으로 이동시킵니다.

gem_exp = GemExperiment(
plaquette_lattice.filter(range(3, 9)), backend=backend
)
gem_exp.set_experiment_options(schedule_idx=0)
exp_data = gem_exp.run(shots=10_000)
exp_data.block_for_results()
exp_data.figure("normalized_variance")

Output of the previous code cell

gem_exp = GemExperiment(plaquette_lattice, backend=backend)
gem_exp.set_experiment_options(schedule_idx=0)
exp_data = gem_exp.run(shots=10_000)
exp_data.block_for_results()
exp_data.figure("normalized_variance")

Output of the previous code cell

결론

이 튜토리얼에서는 GEM 프로토콜을 사용하여 양자 프로세서에서 니시모리 상전이를 구현했습니다. 후처리 중에 검토한 지표, 특히 이점 상관과 정규화된 분산은 장범위 얽힌 상태를 생성하는 장치 능력의 벤치마크 역할을 합니다. 이러한 벤치마크는 GEM 프로토콜의 유용성을 흥미로운 물리 탐구를 넘어 확장합니다. 프로토콜의 일부로, 일정 깊이의 Circuit만을 사용하여 전체 장치에 걸쳐 Qubit들을 얽었습니다. 이 성과는 프로토콜의 중간 Circuit 측정 사용 덕분에 가능합니다. 이 실험에서 얽힌 상태는 즉시 측정되었지만, 추가 양자 처리에서 상태를 계속 사용하는 것도 탐구해볼 흥미로운 방향입니다!

튜토리얼 설문

이 짧은 설문을 통해 튜토리얼에 대한 피드백을 제공해 주세요. 여러분의 의견은 콘텐츠 제공과 사용자 경험 개선에 도움이 됩니다.

설문 링크

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.