Langkau ke kandungan utama

Bekerja dengan DAG dalam transpiler passes

Dalam Qiskit, semasa peringkat transpilasi, litar diwakili menggunakan DAG. Secara amnya, DAG terdiri daripada bucu (juga dikenali sebagai "nod") dan tepi terarah yang menghubungkan pasangan bucu dalam orientasi tertentu. Representasi ini disimpan menggunakan objek qiskit.dagcircuit.DAGCircuit yang terdiri daripada objek DagNode individu. Kelebihan representasi ini berbanding senarai get tulen (iaitu, netlist) ialah aliran maklumat antara operasi adalah eksplisit, menjadikannya lebih mudah untuk membuat keputusan transformasi.

Panduan ini menunjukkan cara bekerja dengan DAG dan menggunakannya untuk menulis transpiler passes khusus. Ia bermula dengan membina litar mudah dan memeriksa representasi DAG-nya, kemudian meneroka operasi DAG asas dan melaksanakan laluan BasicMapper khusus.

Bina litar dan periksa DAG-nya​

Coretan kod di bawah menggambarkan DAG dengan mencipta litar mudah yang menyediakan keadaan Bell dan menggunakan putaran RZR_Z, bergantung pada hasil pengukuran.

Versi pakej

Kod pada halaman ini dibangunkan menggunakan keperluan berikut. Kami mengesyorkan menggunakan versi ini atau yang lebih baharu.

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")

Output of the previous code cell

Dalam DAG, terdapat tiga jenis nod graf: nod input qubit/clbit (hijau), nod operasi (biru), dan nod output (merah). Setiap tepi menunjukkan aliran data (atau kebergantungan) antara dua nod. Gunakan fungsi qiskit.tools.visualization.dag_drawer() untuk melihat DAG litar ini. (Pasang perpustakaan Graphviz untuk menjalankan ini.)

# Convert to DAG
dag = circuit_to_dag(circ)
dag_drawer(dag)

Output of the previous code cell

Operasi DAG asas​

Contoh kod di bawah menunjukkan operasi biasa dengan DAG, termasuk mengakses nod, menambah operasi, dan menggantikan sublitar. Operasi-operasi ini membentuk asas untuk membina transpiler passes.

Dapatkan semua nod operasi dalam DAG​

Kaedah op_nodes() mengembalikan senarai iterable objek DAGOpNode dalam litar:

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>))]

Setiap nod adalah contoh kelas 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)

Tambah operasi di bahagian belakang​

Operasi ditambah ke penghujung DAGCircuit menggunakan kaedah apply_operation_back(). Ini menambahkan get yang dinyatakan untuk bertindak pada qubit yang diberikan selepas semua operasi sedia ada dalam litar.

from qiskit.circuit.library import HGate

dag.apply_operation_back(HGate(), qargs=[q[0]])
dag_drawer(dag)

Output of the previous code cell

Tambah operasi di bahagian hadapan​

Operasi ditambah ke permulaan DAGCircuit menggunakan kaedah apply_operation_front(). Ini memasukkan get yang dinyatakan sebelum semua operasi sedia ada dalam litar, menjadikannya operasi pertama yang dilaksanakan.

from qiskit.circuit.library import CCXGate

dag.apply_operation_front(CCXGate(), qargs=[q[0], q[1], q[2]])
dag_drawer(dag)

Output of the previous code cell

Gantikan nod dengan sublitar​

Nod yang mewakili operasi tertentu dalam DAGCircuit digantikan dengan sublitar. Pertama, sub-DAG baru dibina dengan urutan get yang dikehendaki, kemudian nod sasaran digantikan oleh sub-DAG ini menggunakan substitute_node_with_dag(), mengekalkan sambungan ke bahagian lain litar.

from qiskit.dagcircuit import DAGCircuit
from qiskit.circuit.library import CHGate, U2Gate, CXGate

# Build sub-DAG
mini_dag = DAGCircuit()
p = QuantumRegister(2, "p")
mini_dag.add_qreg(p)
mini_dag.apply_operation_back(CHGate(), qargs=[p[1], p[0]])
mini_dag.apply_operation_back(U2Gate(0.1, 0.2), qargs=[p[1]])

# Replace CX with mini_dag
cx_node = dag.op_nodes(op=CXGate).pop()
dag.substitute_node_with_dag(cx_node, mini_dag, wires=[p[0], p[1]])
dag_drawer(dag)

Output of the previous code cell

Setelah semua transformasi selesai, DAG boleh ditukar semula kepada objek QuantumCircuit biasa. Inilah cara saluran paip Transpiler beroperasi. Litar diambil, diproses dalam bentuk DAG, dan litar yang telah ditransformasi dihasilkan sebagai output.

from qiskit.converters import dag_to_circuit

new_circ = dag_to_circuit(dag)
circuit_drawer(new_circ, output="mpl")

Output of the previous code cell

Laksanakan laluan BasicMapper​

Struktur DAG boleh dimanfaatkan untuk menulis transpiler passes. Dalam contoh di bawah, laluan BasicMapper dilaksanakan untuk memetakan litar sembarangan ke peranti dengan sambungan Qubit yang terhad. Untuk panduan tambahan, rujuk panduan tentang menulis transpiler passes khusus.

Laluan ini ditakrifkan sebagai TransformationPass, bermakna ia mengubah litar. Ia berbuat demikian dengan melintasi DAG lapisan demi lapisan, memeriksa sama ada setiap arahan memenuhi kekangan yang dikenakan oleh peta gandingan peranti. Jika pelanggaran dikesan, laluan swap ditentukan dan get SWAP yang diperlukan dimasukkan sewajarnya.

Apabila mencipta transpiler pass, keputusan pertama melibatkan pemilihan sama ada laluan harus mewarisi daripada TransformationPass atau AnalysisPass. Laluan transformasi direka untuk mengubah litar, manakala laluan analisis hanya bertujuan untuk mengekstrak maklumat untuk digunakan oleh laluan seterusnya. Fungsi utama kemudian dilaksanakan dalam kaedah run(dag). Akhirnya, laluan perlu didaftarkan dalam modul qiskit.transpiler.passes.

Dalam laluan khusus ini, DAG dilintasi lapisan demi lapisan (di mana setiap lapisan mengandungi operasi yang bertindak pada set Qubit yang tidak bertindan dan oleh itu boleh dilaksanakan secara bebas). Untuk setiap operasi, jika kekangan peta gandingan tidak dipenuhi, laluan swap yang sesuai dikenal pasti, dan swap yang diperlukan dimasukkan untuk membawa Qubit yang terlibat ke kedudukan bersebelahan.

from qiskit.transpiler.basepasses import TransformationPass
from qiskit.transpiler import Layout
from qiskit.circuit.library import SwapGate

class BasicSwap(TransformationPass):
def __init__(self, coupling_map, initial_layout=None):
super().__init__()
self.coupling_map = coupling_map
self.initial_layout = initial_layout

def run(self, dag):
new_dag = DAGCircuit()
for qreg in dag.qregs.values():
new_dag.add_qreg(qreg)
for creg in dag.cregs.values():
new_dag.add_creg(creg)

if self.initial_layout is None:
self.initial_layout = Layout.generate_trivial_layout(
*dag.qregs.values()
)

current_layout = self.initial_layout.copy()

for layer in dag.serial_layers():
subdag = layer["graph"]
for gate in subdag.two_qubit_ops():
q0, q1 = gate.qargs
p0 = current_layout[q0]
p1 = current_layout[q1]

if self.coupling_map.distance(p0, p1) != 1:
path = self.coupling_map.shortest_undirected_path(p0, p1)
for i in range(len(path) - 2):
wire1, wire2 = path[i], path[i + 1]
qubit1 = current_layout[wire1]
qubit2 = current_layout[wire2]
new_dag.apply_operation_back(
SwapGate(), qargs=[qubit1, qubit2]
)
current_layout.swap(wire1, wire2)

new_dag.compose(
subdag, qubits=current_layout.reorder_bits(new_dag.qubits)
)

return new_dag

Laluan kini boleh diuji pada litar contoh kecil. Pengurus laluan dibina dengan laluan yang baru ditakrifkan disertakan. Litar contoh kemudian diberikan kepada pengurus laluan ini, dan litar baru yang telah ditransformasi diperoleh sebagai output.

from qiskit.transpiler import CouplingMap, PassManager
from qiskit import QuantumRegister, QuantumCircuit

q = QuantumRegister(7, "q")
in_circ = QuantumCircuit(q)
in_circ.h(q[0])
in_circ.cx(q[0], q[4])
in_circ.cx(q[2], q[3])
in_circ.cx(q[6], q[1])
in_circ.cx(q[5], q[0])
in_circ.rz(0.1, q[2])
in_circ.cx(q[5], q[0])

coupling = [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 6]]
coupling_map = CouplingMap(couplinglist=coupling)

pm = PassManager()
pm.append(BasicSwap(coupling_map))

out_circ = pm.run(in_circ)

in_circ.draw(output="mpl")
out_circ.draw(output="mpl")

Output of the previous code cell

Langkah seterusnya​

Source: IBM Quantum docs β€” updated 27 Apr 2026
English version on doQumentation β€” updated 7 Mei 2026
This translation based on the English version of 11 Mac 2026