주 콘텐츠로 건너뛰기

Transpiler를 위한 양자 컴퓨터 표현하기

패키지 버전

이 페이지의 코드는 다음 요구 사항을 사용하여 개발되었습니다. 이 버전 이상을 사용하는 것을 권장합니다.

qiskit[all]~=2.3.0
qiskit-ibm-runtime~=0.43.1

추상 Circuit을 특정 QPU(양자 처리 장치)에서 실행할 수 있는 ISA Circuit으로 변환하려면, Transpiler가 QPU에 대한 특정 정보를 필요로 합니다. 이 정보는 두 곳에서 찾을 수 있습니다: 작업을 제출할 BackendV2(또는 레거시 BackendV1) 객체와 Backend의 Target 속성입니다.

  • Target은 기기의 모든 관련 제약 조건, 즉 기본 기저 Gate, Qubit 연결성, 펄스 또는 타이밍 정보 등을 포함합니다.
  • Backend는 기본적으로 Target을 보유하며, InstructionScheduleMap과 같은 추가 정보를 포함하고, 양자 Circuit 작업 제출을 위한 인터페이스를 제공합니다.

또한 특정 사용 사례가 있거나 이 정보가 Transpiler가 더 최적화된 Circuit을 생성하는 데 도움이 된다고 판단되는 경우, Transpiler가 사용할 정보를 명시적으로 제공할 수도 있습니다.

Transpiler가 특정 하드웨어에 가장 적합한 Circuit을 얼마나 정밀하게 생성하는지는 Target 또는 Backend가 제약 조건에 대해 얼마나 많은 정보를 보유하고 있는지에 달려 있습니다.

참고

기본 트랜스파일 알고리즘 중 다수가 확률론적이기 때문에, 더 나은 Circuit이 발견된다는 보장은 없습니다.

이 페이지에서는 QPU 정보를 Transpiler에 전달하는 여러 예제를 살펴봐요. 이 예제들은 FakeSherbrooke 모의 Backend의 Target을 사용합니다.

기본 구성

Transpiler를 가장 간단하게 사용하는 방법은 Backend 또는 Target을 제공하여 모든 QPU 정보를 제공하는 것입니다. Transpiler가 어떻게 작동하는지 더 잘 이해하려면, 아래와 같이 Circuit을 구성하고 다양한 정보로 트랜스파일해 보세요.

필요한 라이브러리를 가져오고 QPU를 인스턴스화합니다: 추상 Circuit을 특정 프로세서에서 실행할 수 있는 ISA Circuit으로 변환하기 위해, Transpiler는 프로세서에 대한 특정 정보를 필요로 합니다. 일반적으로 이 정보는 Transpiler에 제공되는 Backend 또는 Target에 저장되며, 추가 정보는 필요하지 않습니다. 그러나 특정 사용 사례가 있거나 이 정보가 Transpiler가 더 최적화된 Circuit을 생성하는 데 도움이 된다고 판단되는 경우, Transpiler가 사용할 정보를 명시적으로 제공할 수도 있습니다.

이 항목에서는 Transpiler에 정보를 전달하는 여러 예제를 살펴봐요. 이 예제들은 FakeSherbrooke 모의 Backend의 Target을 사용합니다.

# Added by doQumentation — required packages for this notebook
!pip install -q qiskit qiskit-ibm-runtime
from qiskit_ibm_runtime.fake_provider import FakeSherbrooke

backend = FakeSherbrooke()
target = backend.target

예제 Circuit은 Qiskit의 Circuit 라이브러리에서 efficient_su2의 인스턴스를 사용합니다.

from qiskit.circuit.library import efficient_su2

qc = efficient_su2(12, entanglement="circular", reps=1)

qc.draw("mpl")

이전 코드 셀의 출력

이 예제는 기본 설정을 사용하여 backendtarget으로 트랜스파일합니다. 이 Target은 Circuit을 Backend에서 실행할 수 있는 형태로 변환하는 데 필요한 모든 정보를 제공합니다.

from qiskit.transpiler import generate_preset_pass_manager

pass_manager = generate_preset_pass_manager(
optimization_level=1, target=target, seed_transpiler=12345
)
qc_t_target = pass_manager.run(qc)
qc_t_target.draw("mpl", idle_wires=False, fold=-1)

이전 코드 셀의 출력

이 예제는 이 항목의 이후 섹션에서 커플링 맵과 기저 Gate가 최적의 Circuit 구성을 위해 Transpiler에 전달해야 할 필수 정보임을 설명하는 데 사용됩니다. QPU는 일반적으로 타이밍 및 스케줄링과 같이 전달되지 않은 다른 정보에 대해 기본 설정을 선택할 수 있습니다.

커플링 맵

커플링 맵은 어떤 Qubit들이 연결되어 있고 따라서 두 Qubit Gate를 가지는지를 보여주는 그래프입니다. 때로는 이 그래프가 방향성을 가지며, 이는 두 Qubit Gate가 한 방향으로만 적용될 수 있음을 의미합니다. 그러나 Transpiler는 추가적인 단일 Qubit Gate를 추가하여 Gate의 방향을 항상 반전시킬 수 있습니다. 추상 양자 Circuit은 SWAP Gate를 도입하여 양자 정보를 이동시킴으로써, 연결성이 제한되어 있더라도 항상 이 그래프에서 표현될 수 있습니다.

추상 Circuit의 Qubit을 _가상 Qubit_이라고 하며, 커플링 맵의 Qubit을 _물리적 Qubit_이라고 합니다. Transpiler는 가상 Qubit과 물리적 Qubit 사이의 매핑을 제공합니다. 트랜스파일의 첫 번째 단계 중 하나인 레이아웃 단계에서 이 매핑을 수행합니다.

참고

라우팅 단계는 실제 Qubit을 선택하는 레이아웃 단계와 얽혀 있지만, 이 항목에서는 기본적으로 단순화를 위해 별개의 단계로 다룹니다. 라우팅과 레이아웃의 조합을 _Qubit 매핑_이라고 합니다. 이러한 단계에 대한 자세한 내용은 Transpiler 단계 항목에서 확인하세요.

coupling_map 키워드 인수를 전달하여 Transpiler에 미치는 영향을 확인해 보세요:

coupling_map = target.build_coupling_map()

pass_manager = generate_preset_pass_manager(
optimization_level=0, coupling_map=coupling_map, seed_transpiler=12345
)
qc_t_cm_lv0 = pass_manager.run(qc)
qc_t_cm_lv0.draw("mpl", idle_wires=False, fold=-1)

이전 코드 셀의 출력

위에서 보이듯이, 여러 SWAP Gate가 삽입되었습니다(각각 세 개의 CX Gate로 구성됨). 이는 현재 장치에서 많은 오류를 유발할 것입니다. 실제 Qubit 토폴로지에서 어떤 Qubit이 선택되었는지 확인하려면, Qiskit 시각화에서 plot_circuit_layout을 사용하세요:

from qiskit.visualization import plot_circuit_layout

plot_circuit_layout(qc_t_cm_lv0, backend, view="physical")

이전 코드 셀의 출력

이는 가상 Qubit 0-11이 물리적 Qubit 0-11의 라인에 단순하게 매핑되었음을 보여줍니다. 라우팅이 필요한 경우 VF2Layout을 사용하는 기본값(optimization_level=1)으로 돌아가겠습니다.

pass_manager = generate_preset_pass_manager(
optimization_level=1, coupling_map=coupling_map, seed_transpiler=12345
)
qc_t_cm_lv1 = pass_manager.run(qc)
qc_t_cm_lv1.draw("mpl", idle_wires=False, fold=-1)

이전 코드 셀의 출력

이제 SWAP Gate가 삽입되지 않았으며, 선택된 물리적 Qubit은 target 클래스를 사용할 때와 동일합니다.

from qiskit.visualization import plot_circuit_layout

plot_circuit_layout(qc_t_cm_lv1, backend, view="physical")

이전 코드 셀의 출력

이제 레이아웃이 링 형태입니다. 이 레이아웃은 Circuit의 연결성을 존중하기 때문에 SWAP Gate가 없으며, 실행에 훨씬 더 좋은 Circuit을 제공합니다.

기저 Gate

모든 양자 컴퓨터는 제한된 명령어 집합, 즉 _기저 Gate_를 지원합니다. Circuit의 모든 Gate는 이 집합의 요소로 변환되어야 합니다. 이 집합은 단일 및 두 Qubit Gate로 구성되어야 하며, 범용 Gate 집합을 제공해야 합니다. 즉, 어떤 양자 연산도 해당 Gate들로 분해될 수 있어야 합니다. 이는 BasisTranslator에 의해 수행되며, 기저 Gate는 이 정보를 제공하기 위해 Transpiler에 키워드 인수로 지정할 수 있습니다.

basis_gates = list(target.operation_names)
print(basis_gates)
['sx', 'switch_case', 'x', 'if_else', 'measure', 'for_loop', 'delay', 'ecr', 'id', 'reset', 'rz']

_ibm_sherbrooke_의 기본 단일 Qubit Gate는 rz, x, sx이며, 기본 두 Qubit Gate는 ecr(에코된 크로스-레조넌스)입니다. CX Gate는 ecr Gate로 구성되므로, 일부 QPU에서는 ecr이 두 Qubit 기저 Gate로 지정되고, 다른 QPU에서는 cx가 기본값입니다. ecr Gate는 cx Gate의 얽힘 부분입니다. 제어 Gate 외에도 delaymeasurement 명령어도 있습니다.

참고

QPU는 기본 기저 Gate를 가지고 있지만, 명령어를 제공하거나 펄스 Gate를 추가하는 한 원하는 Gate를 선택할 수 있습니다(Transpiler 패스 만들기 참조). 기본 기저 Gate는 QPU에서 캘리브레이션이 완료된 Gate이므로 추가 명령어/펄스 Gate를 제공할 필요가 없습니다. 예를 들어, 일부 QPU에서는 cx가 기본 두 Qubit Gate이고 다른 QPU에서는 ecr입니다. 자세한 내용은 가능한 기본 Gate 및 연산 목록을 참조하세요.

pass_manager = generate_preset_pass_manager(
optimization_level=1,
coupling_map=coupling_map,
basis_gates=basis_gates,
seed_transpiler=12345,
)
qc_t_cm_bg = pass_manager.run(qc)
qc_t_cm_bg.draw("mpl", idle_wires=False, fold=-1)

이전 코드 셀의 출력

CXGate 객체가 ecr Gate와 단일 Qubit 기저 Gate로 분해되었음을 확인하세요.

장치 오류율

Target 클래스는 장치의 연산에 대한 오류율 정보를 포함할 수 있습니다. 예를 들어, 다음 코드는 Qubit 1과 0 사이의 에코된 크로스-레조넌스(ECR) Gate의 속성을 검색합니다(ECR Gate는 방향성이 있음에 유의하세요):

target["ecr"][(1, 0)]
InstructionProperties(duration=5.333333333333332e-07, error=0.007494257741828603)

출력에는 Gate의 지속 시간(초 단위)과 오류율이 표시됩니다. Transpiler에 오류 정보를 노출하려면, 위의 basis_gatescoupling_map으로 Target 모델을 구축하고 Backend FakeSherbrooke의 오류 값으로 채우세요.

from qiskit.transpiler import Target
from qiskit.circuit.controlflow import IfElseOp, SwitchCaseOp, ForLoopOp

err_targ = Target.from_configuration(
basis_gates=basis_gates,
coupling_map=coupling_map,
num_qubits=target.num_qubits,
custom_name_mapping={
"if_else": IfElseOp,
"switch_case": SwitchCaseOp,
"for_loop": ForLoopOp,
},
)

for i, (op, qargs) in enumerate(target.instructions):
if op.name in basis_gates:
err_targ[op.name][qargs] = target.instruction_properties(i)

새로운 Target err_targ를 Target으로 사용하여 트랜스파일합니다:

pass_manager = generate_preset_pass_manager(
optimization_level=1, target=err_targ, seed_transpiler=12345
)
qc_t_cm_bg_et = pass_manager.run(qc)
qc_t_cm_bg_et.draw("mpl", idle_wires=False, fold=-1)

이전 코드 셀의 출력

Target에 오류 정보가 포함되어 있기 때문에, VF2PostLayout 패스는 사용할 최적의 Qubit을 찾으려고 시도하며, 그 결과 동일한 물리적 Qubit을 사용하여 처음에 찾은 것과 동일한 Circuit이 생성됩니다.

다음 단계

권장 사항