트랜스파일러 패스에서 DAG 사용하기
Qiskit에서는 트랜스파일 단계 내에서 Circuit이 DAG를 사용하여 표현됩니다. 일반적으로 DAG는 정점(노드라고도 함)과 정점 쌍을 특정 방향으로 연결하는 방향성 엣지로 구성됩니다. 이 표현은 개별 DagNode 객체로 구성된 qiskit.dagcircuit.DAGCircuit 객체를 사용하여 저장됩니다. 순수한 Gate 목록(즉, 넷리스트) 대비 이 표현의 장점은 연산 간 정보 흐름이 명시적으로 드러나 변환 결정을 내리기가 더 쉽다는 점입니다.
이 가이드에서는 DAG를 다루고 이를 활용하여 커스텀 Transpiler 패스를 작성하는 방법을 설명합니다. 먼저 간단한 Circuit을 구성하고 DAG 표현을 살펴본 후, 기본적인 DAG 연산을 탐색하고 커스텀 BasicMapper 패스를 구현합니다.
Circuit 구성 및 DAG 살펴보기
아래 코드 예시는 Bell 상태를 준비하고 측정 결과에 따라 회전을 적용하는 간단한 Circuit을 만들어 DAG를 설명합니다.
패키지 버전
이 페이지의 코드는 다음 요구 사항을 사용하여 개발되었습니다. 해당 버전 이상을 사용하길 권장합니다.
qiskit[all]~=2.3.0
# Added by doQumentation — required packages for this notebook
!pip install -q qiskit
from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit
from qiskit.converters import circuit_to_dag
from qiskit.visualization import circuit_drawer
from qiskit.visualization.dag_visualization import dag_drawer
# Create circuit
q = QuantumRegister(3, "q")
c = ClassicalRegister(3, "c")
circ = QuantumCircuit(q, c)
circ.h(q[0])
circ.cx(q[0], q[1])
circ.measure(q[0], c[0])
# Qiskit 2.0 uses if_test instead of c_if
with circ.if_test((c, 2)):
circ.rz(0.5, q[1])
circuit_drawer(circ, output="mpl")
DAG에는 세 가지 종류의 그래프 노드가 있습니다: Qubit/clbit 입력 노드(녹색), 연산 노드(파란색), 출력 노드(빨간색). 각 엣지는 두 노드 간의 데이터 흐름(또는 의존성)을 나타냅니다. qiskit.tools.visualization.dag_drawer() 함수를 사용하여 이 Circuit의 DAG를 시각화할 수 있습니다. (이를 실행하려면 Graphviz 라이브러리를 설치하세요.)
# Convert to DAG
dag = circuit_to_dag(circ)
dag_drawer(dag)

기본 DAG 연산
아래 코드 예시는 노드 접근, 연산 추가, 서브 Circuit 대체 등 DAG와 관련된 일반적인 연산을 보여줍니다. 이러한 연산들은 Transpiler 패스를 구축하기 위한 기반이 됩니다.
DAG의 모든 연산 노드 가져오기
op_nodes() 메서드는 Circuit 내 DAGOpNode 객체의 이터러블 리스트를 반환합니다:
dag.op_nodes()
[DAGOpNode(op=Instruction(name='h', num_qubits=1, num_clbits=0, params=[]), qargs=(<Qubit register=(3, "q"), index=0>,), cargs=()),
DAGOpNode(op=Instruction(name='cx', num_qubits=2, num_clbits=0, params=[]), qargs=(<Qubit register=(3, "q"), index=0>, <Qubit register=(3, "q"), index=1>), cargs=()),
DAGOpNode(op=Instruction(name='measure', num_qubits=1, num_clbits=1, params=[]), qargs=(<Qubit register=(3, "q"), index=0>,), cargs=(<Clbit register=(3, "c"), index=0>,)),
DAGOpNode(op=Instruction(name='if_else', num_qubits=1, num_clbits=3, params=[<qiskit.circuit.quantumcircuit.QuantumCircuit object at 0x7f912f47db10>, None]), qargs=(<Qubit register=(3, "q"), index=1>,), cargs=(<Clbit register=(3, "c"), index=0>, <Clbit register=(3, "c"), index=1>, <Clbit register=(3, "c"), index=2>))]
각 노드는 DAGOpNode 클래스의 인스턴스입니다:
node = dag.op_nodes()[3]
print("node name:", node.name)
print("op:", node.op)
print("qargs:", node.qargs)
print("cargs:", node.cargs)
print("condition:", node.op.condition)
node name: if_else
op: Instruction(name='if_else', num_qubits=1, num_clbits=3, params=[<qiskit.circuit.quantumcircuit.QuantumCircuit object at 0x7f912f4ceed0>, None])
qargs: (<Qubit register=(3, "q"), index=1>,)
cargs: (<Clbit register=(3, "c"), index=0>, <Clbit register=(3, "c"), index=1>, <Clbit register=(3, "c"), index=2>)
condition: (ClassicalRegister(3, 'c'), 2)
뒤에 연산 추가하기
apply_operation_back() 메서드를 사용하여 DAGCircuit의 끝에 연산을 추가합니다. 이렇게 하면 Circuit 내 기존 연산들 이후에 지정된 Gate가 해당 Qubit에 적용되도록 추가됩니다.
from qiskit.circuit.library import HGate
dag.apply_operation_back(HGate(), qargs=[q[0]])
dag_drawer(dag)
