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

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)

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)

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)

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")
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")
Langkah seterusnyaβ
- Semak panduan tentang mencipta transpiler pass khusus
- Pelajari cara Cipta dan transpil terhadap Backend khusus
- Cuba panduan Bandingkan tetapan Transpiler.
- Semak dokumentasi API DAG Circuit.