동적 Circuit 실행
패키지 버전
이 페이지의 코드는 다음 요구 사항을 사용하여 개발되었습니다. 이 버전 이상을 사용하는 것을 권장합니다.
qiskit[all]~=2.4.0
qiskit-ibm-runtime~=0.46.1
동적 Circuit은 양자 Circuit 실행 중간에 Qubit을 측정하고, 해당 중간 회로 측정 결과를 기반으로 Circuit 내에서 고전 논리 연산을 수행할 수 있는 강력한 도구입니다. 이 프로세스는 _고전적 피드포워드_라고도 합니다. 동적 Circuit을 최대한 활용하는 방법에 대한 이해는 아직 초기 단계이지만, 양자 연구 커뮤니티는 이미 다음과 같은 여러 사용 사례를 확인했습니다:
- GHZ 상태, W-상태(W-상태에 대한 자세한 내용은 "피드포워드를 사용한 얕은 Circuit에 의한 상태 준비"도 참조)와 같은 효율적인 양자 상태 준비, 그리고 광범위한 행렬 곱 상태
- 얕은 Circuit을 사용하여 동일한 칩의 Qubit 간 효율적인 장거리 얽힘
- IQP 유사 Circuit의 효율적인 샘플링
그러나 동적 Circuit으로 인한 이러한 개선에는 트레이드오프가 따릅니다. 중간 회로 측정과 고전 연산은 일반적으로 2-Qubit Gate보다 실행 시간이 더 길며, 이 시간 증가가 회로 깊이 감소의 이점을 상쇄할 수 있습니다. 따라서 중간 회로 측정 길이 단축은 IBM Quantum®이 동적 Circuit의 새 버전을 출시함에 따라 개선의 핵심 영역입니다. 동적 Circuit 사용 시의 다른 제한 사항은 Estimator 또는 Sampler 기능 호환성 표를 참조하세요.
OpenQASM 3 명세는 다수의 제어 흐름 구조를 정의하지만, Qiskit Runtime은 현재 조건부 if 문만 지원합니다. Qiskit SDK에서 이는 QuantumCircuit의 if_test 메서드에 해당합니다. 이 메서드는 컨텍스트 관리자를 반환하며 일반적으로 with 문에서 사용됩니다. 이 가이드에서는 이 조건문 사용 방법을 설명합니다.
이 가이드의 코드 예제는 중간 회로 측정에 표준 measure 명령을 사용합니다. 그러나 Backend가 지원하는 경우 MidCircuitMeasure 명령을 대신 사용하는 것이 권장됩니다. 자세한 내용은 중간 회로 측정 섹션을 참조하세요.
동적 Circuit을 지원하는 Backend 찾기
계정이 접근할 수 있고 동적 Circuit을 지원하는 모든 Backend를 찾으려면 다음과 같은 코드를 실행하세요. 이 예제는 로그인 자격 증명을 저장했다고 가정합니다. Qiskit Runtime 서비스 계정을 초기화할 때 명시적으로 자격 증명을 지정할 수도 있습니다. 예를 들어 특정 인스턴스나 플랜 유형에서 사용 가능한 Backend를 확인할 수 있습니다.
- 계정에서 사용 가능한 Backend는 자격 증명에서 지정된 인스턴스에 따라 다릅니다.
- 동적 Circuit의 새 버전은 이제 모든 Backend의 모든 사용자에게 제공됩니다. 자세한 내용은 공지 사항을 참조하세요.
# Added by doQumentation — required packages for this notebook
!pip install -q qiskit qiskit-ibm-runtime
# This cell is hidden from users. It hides all those "...instance was not set..." warnings.
import warnings
warnings.filterwarnings("ignore", message=".*Instance was not set*")
from qiskit_ibm_runtime import QiskitRuntimeService
service = QiskitRuntimeService()
dc_backends = service.backends(dynamic_circuits=True)
print(dc_backends)
[<IBMBackend('ibm_pittsburgh')>, <IBMBackend('ibm_kingston')>, <IBMBackend('ibm_marrakesh')>, <IBMBackend('ibm_fez')>, <IBMBackend('ibm_boston')>]
중간 회로 측정
qiskit-ibm-runtime v0.43.0 이전에는 measure가 Qiskit의 유일한 측정 명령이었습니다. 그러나 중간 회로 측정은 터미널 측정(Circuit 끝에서 수행되는 측정)과는 다른 튜닝 요구 사항을 가집니다. 예를 들어, 중간 회로 측정을 튜닝할 때는 명령 지속 시간을 고려해야 하는데, 더 긴 명령은 더 노이즈가 많은 Circuit을 만들기 때문입니다. 터미널 측정 후에는 명령이 없으므로 터미널 측정에서는 명령 지속 시간을 고려할 필요가 없습니다.
MidCircuitMeasure 명령은 Backend의 supported_instructions에 보고된 measure_2 명령에 매핑됩니다. 그러나 measure_2는 모든 Backend에서 지원되지는 않습니다. service.backends(filters=lambda b: "measure_2" in b.supported_instructions)를 사용하여 이를 지원하는 Backend를 찾으세요. 향후 새 측정 명령이 추가될 수 있지만, 이는 보장되지 않습니다.
MidCircuitMeasure 메서드
qiskit-ibm-runtime v0.43.0에서 MidCircuitMeasure 명령이 도입되었습니다. 이름에서 알 수 있듯이, IBM® QPU에서 중간 회로에 최적화된 새로운 측정 명령입니다. 중간 회로 측정에 QuantumCircuit.measure를 사용할 수 있지만, 설계 특성상 MidCircuitMeasure가 일반적으로 더 나은 선택입니다. 예를 들어, QuantumCircuit.measure를 사용할 때보다 Circuit에 더 적은 오버헤드를 추가합니다.
from qiskit import QuantumCircuit
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime.circuit import MidCircuitMeasure
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, dynamic_circuits=True
)
circ = QuantumCircuit(2, 2)
circ.x(0)
circ.append(MidCircuitMeasure(), [0], [0])
# circ.measure([0], [0])
# circ.measure_all()
print(circ.draw(cregbundle=False))
┌───┐┌────────────┐
q_0: ┤ X ├┤0 ├
└───┘│ │
q_1: ─────┤ Measure_2 ├
│ │
c_0: ═════╡0 ╞
└────────────┘
c_1: ═══════════════════
- 측정을 사용하려면 최소한 하나의 고전 레지스터가 있어야 합니다.
- Sampler Primitive는 Circuit 측정이 필요합니다. Estimator Primitive에서는 Circuit 측정을 추가할 수 있지만 무시됩니다.
Store
qiskit-ibm-runtime 버전 0.47.0 이상에서는 store 명령을 사용하여 고전 표현식의 결과를 저장할 수 있습니다. 이는 해당 표현식이 반복적으로 사용될 경우에 유용합니다. 연산은 자동으로 병렬화되어 런타임 시 코드의 효율이 크게 향상됩니다.
자세한 내용은 고전적 피드포워드 및 제어 흐름 가이드를 참조하세요.
실제 Backend에서 store를 사용하여 값을 고전 레지스터에 저장하면, 해당 값은 실행 중에만 메모리에 저장되며 Job 결과에는 복사되거나 반환되지 않습니다.
예를 들어, 다음 코드에서 temp는 실행 중에 creg와 동일한 값을 가지며 if_test는 예상대로 작동합니다. 그러나 Job이 완료된 후, Job 결과에서 반환된 temp BitArray는 creg의 값을 포함하지 않습니다. 즉, job.result()[0].data.temp는 0입니다.
creg = ClassicalRegister(3, "c")
temp = ClassicalRegister(3, "temp")
...
qc.store(temp, creg)
with circuit.if_test((temp, 0b001)):
...
전체 예제
다음 코드는 IBM® 하드웨어에서 동적 Circuit을 생성하고 실행합니다.
from qiskit_ibm_runtime import SamplerV2, QiskitRuntimeService
from qiskit.circuit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit.transpiler import generate_preset_pass_manager
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, dynamic_circuits=True
)
# Create a dynamic circuit
qubits = QuantumRegister(1)
clbits = ClassicalRegister(1)
qc = QuantumCircuit(qubits, clbits)
(q0,) = qubits
(c0,) = clbits
qc.h(q0)
qc.measure(q0, c0)
with qc.if_test((c0, 1)):
qc.x(q0)
qc.measure(q0, c0)
# Convert to an ISA circuit for the given backend
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuit = pm.run(qc)
# Generate samplers for backend targets
sampler = SamplerV2(backend)
# Submit jobs
sampler_job = sampler.run([isa_circuit])
result = sampler_job.result()
print(
f">>> {' Job ID:':<10} {sampler_job.job_id()} ({sampler_job.status()})"
)
>>> Job ID: d88cakp789is7391vq0g (DONE)
Qiskit Runtime 제한 사항
Qiskit Runtime에서 동적 Circuit을 실행할 때 다음 제약 사항에 유의하세요.
-
제어 전자 장치의 제한된 물리 메모리로 인해
if문의 수와 피연산자 크기에도 제한이 있습니다. 이 제한은 Job(Circuit이 아님)에서 브로드캐스트 수와 브로드캐스트된 비트 수의 함수입니다.if조건을 처리할 때 제어 로직이 평가를 수행하기 위해 측정 데이터를 전송해야 합니다. 브로드캐스트는 고유한 고전 데이터의 전송이며, 브로드캐스트된 비트는 전송되는 고전 비트의 수입니다. 다음을 고려하세요:c0 = ClassicalRegister(3)c1 = ClassicalRegister(5)...with circuit.if_test((c0, 1)) ...with circuit.if_test((c0, 3)) ...with circuit.if_test((c1[2], 1)) ...이전 코드 예제에서
c0에 대한 처음 두if_test객체는c0의 내용이 변경되지 않아 다시 브로드캐스트할 필요가 없으므로 하나의 브로드캐스트로 간주됩니다.c1의if_test는 두 번째 브로드캐스트입니다. 첫 번째는c0의 세 비트를 모두 브로드캐스트하고 두 번째는 하나의 비트만 브로드캐스트하여 총 네 개의 브로드캐스트된 비트가 됩니다.현재 매번 60비트를 브로드캐스트하면 Job에는 약 300번의 브로드캐스트가 가능합니다. 그러나 매번 1비트만 브로드캐스트하면 Job에는 2400번의 브로드캐스트가 가능합니다.
-
if_test문에서 사용되는 피연산자는 32비트 이하여야 합니다. 따라서 전체ClassicalRegister를 비교하는 경우 해당ClassicalRegister의 크기가 32비트 이하여야 합니다. 그러나ClassicalRegister의 단일 비트만 비교하는 경우 피연산자가 하나의 비트뿐이므로 해당ClassicalRegister는 어떤 크기도 가능합니다.예를 들어, "유효하지 않음" 코드 블록은
cr이 32비트를 초과하기 때문에 작동하지 않습니다. 그러나 "유효함" 코드 블록에서 보여주는 것처럼 하나의 비트만 테스트하는 경우에는 32비트보다 넓은 고전 레지스터를 사용할 수 있습니다.- 유효하지 않음
- 유효함
cr = ClassicalRegister(50)qr = QuantumRegister(50)circuit = QuantumCircuit(qr, cr)...circ.measure(qr, cr)with circ.if_test((cr, 15)):...cr = ClassicalRegister(50)qr = QuantumRegister(50)circuit = QuantumCircuit(qr, cr)...circ.measure(qr, cr)with circ.if_test((cr[5], 1)):... -
중첩 조건문은 허용되지 않습니다. 예를 들어, 다음 코드 블록은
if_test내부에 또 다른if_test가 있어서 작동하지 않습니다:- 유효하지 않음
- 유효함
c1 = ClassicalRegister(1, "c1")c2 = ClassicalRegister(2, "c2")...with circ.if_test((c1, 1)):with circ.if_test(c2, 1)):...cr = ClassicalRegister(2)...with circuit.if_test((cr, 0b11)):... -
조건문 내부의
reset또는 측정은 지원되지 않습니다. -
산술 연산은 지원되지 않습니다.
-
Qiskit 및 Qiskit Runtime에서 지원되는 OpenQASM 3 기능을 확인하려면 OpenQASM 3 기능 표를 참조하세요.
-
Qiskit Runtime Primitive에 Circuit을 전달하는 입력 형식으로
QuantumCircuit대신 OpenQASM 3을 사용하는 경우, Qiskit에 로드할 수 있는 명령만 지원됩니다. 예를 들어, 고전 연산은 Qiskit에 로드할 수 없으므로 지원되지 않습니다. 자세한 내용은 OpenQASM 3 프로그램을 Qiskit으로 가져오기를 참조하세요. -
for,while,switch명령은 지원되지 않습니다.
Estimator와 함께 동적 Circuit 사용
Estimator는 동적 Circuit을 지원하지 않으므로, Sampler를 사용하고 직접 측정 Circuit을 구축할 수 있습니다.
Estimator의 동작을 재현하려면 다음 프로세스를 따르세요:
- 모든 Observable의 항목을 파티션으로 그룹화합니다. 이는 예를 들어
PauliListAPI를 사용하여 수행할 수 있습니다.참고BitArrayPrimitive 속성을 사용하여 제공된 Observable의 기댓값을 계산할 수 있습니다. - 파티션당 하나의 기저 변환 Circuit을 실행합니다(각 파티션에 대해 수행해야 하는 기저 변환). 자세한 내용은 측정 기저 애드온 유틸리티
measurement_bases모듈을 참조하세요. 자세한 내용은 Qiskit 애드온 유틸리티 패키지의 문서를 참조하세요. - 각 파티션의 결과를 다시 합산합니다.
제한 사항
동적 Circuit 사용 시의 제한 사항을 이해하려면 기능 호환성 표를 검토하세요. 기능 호환성은 Primitive에 의존하지 않습니다.
다음 단계
- 스트레치를 사용하여 정확한 동적 분리를 구현하는 방법을 알아보세요.
- 고전적 피드포워드 및 제어 흐름 가이드를 검토하세요.
- Circuit 스케줄 시각화를 사용하여 동적 Circuit을 디버그하고 최적화하세요.
- 모든 함수가 동적 Circuit과 호환되는 것은 아닙니다. 자세한 내용은 Sampler 또는 Executor의 기능 호환성 섹션을 확인하세요.