ข้ามไปยังเนื้อหาหลัก

การปรับแต่ง Quantum Circuit

หมายเหตุ

Toshinari Itoko (21 มิถุนายน 2024)

ดาวน์โหลด pdf ของบรรยายต้นฉบับ โปรดทราบว่าโค้ดบางส่วนอาจล้าสมัยเนื่องจากเป็นภาพนิ่ง

เวลา QPU โดยประมาณสำหรับการรันการทดลองนี้คือ 15 วินาที

(หมายเหตุ: เซลล์บางส่วนในพาร์ต 2 คัดลอกมาจาก notebook "Qiskit Deep dive" เขียนโดย Matthew Treinish (Qiskit maintainer))

# Added by doQumentation — required packages for this notebook
!pip install -q qiskit qiskit-aer qiskit-ibm-runtime
# !pip install 'qiskit[visualization]'
# !pip install qiskit_ibm_runtime qiskit_aer
# !pip install jupyter
# !pip install matplotlib pylatexenc pydot pillow
import qiskit

qiskit.__version__
'2.0.2'
import qiskit_ibm_runtime

qiskit_ibm_runtime.__version__
'0.40.1'
import qiskit_aer

qiskit_aer.__version__
'0.17.1'

1. บทนำ

บทเรียนนี้จะครอบคลุมหลายแง่มุมของการปรับแต่ง Circuit ในการประมวลผลควอนตัม โดยเฉพาะอย่างยิ่ง เราจะเห็นคุณค่าของการปรับแต่ง Circuit โดยใช้การตั้งค่าการปรับแต่งที่มีใน Qiskit จากนั้นเราจะลงลึกมากขึ้นและดูว่าคุณในฐานะผู้เชี่ยวชาญในสาขาแอปพลิเคชันของตนเองสามารถทำอะไรได้บ้างเพื่อสร้าง Circuit อย่างชาญฉลาด และสุดท้าย เราจะมองอย่างใกล้ชิดว่าเกิดอะไรขึ้นในระหว่างการ Transpile ที่ช่วยให้เราปรับแต่ง Circuit ได้

2. การปรับแต่ง Circuit มีความสำคัญ

เราเปรียบเทียบผลลัพธ์ของการรัน Circuit เตรียมสถานะ GHZ 5-Qubit (12(00000+11111)\frac{1}{\sqrt{2}} \left( |00000\rangle + |11111\rangle \right)) แบบมีและไม่มีการปรับแต่ง

from qiskit.circuit import QuantumCircuit
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit.primitives import BackendSamplerV2 as Sampler
from qiskit_ibm_runtime.fake_provider import FakeBrisbane

backend = FakeBrisbane()

เราเริ่มต้นด้วยการใช้ GHZ Circuit ที่สังเคราะห์แบบง่าย ๆ ดังนี้

num_qubits = 5

ghz_circ = QuantumCircuit(num_qubits)
ghz_circ.h(0)
[ghz_circ.cx(0, i) for i in range(1, num_qubits)]
ghz_circ.measure_all()
ghz_circ.draw("mpl")

Output of the previous code cell

2.1 ระดับการปรับแต่ง

มี optimization_level ให้เลือก 4 ระดับตั้งแต่ 0-3 ยิ่งระดับการปรับแต่งสูงเท่าใด ก็จะใช้ความพยายามในการคำนวณมากขึ้นเพื่อปรับแต่ง Circuit ระดับ 0 ไม่ทำการปรับแต่งใด ๆ และทำเพียงขั้นต่ำที่จำเป็นเพื่อให้ Circuit สามารถรันบน Backend ที่เลือกได้ ระดับ 3 ใช้ความพยายาม (และโดยทั่วไปใช้เวลาในการรัน) มากที่สุดเพื่อพยายามปรับแต่ง Circuit ระดับ 1 คือระดับการปรับแต่งเริ่มต้น เราทำการ Transpile Circuit โดยไม่มีการปรับแต่ง (optimization_level=0) และมีการปรับแต่ง (optimization_level=2) เราเห็นความแตกต่างอย่างมากในความยาวของ Circuit ที่ผ่านการ Transpile แล้ว

pm0 = generate_preset_pass_manager(
optimization_level=0, backend=backend, seed_transpiler=777
)
pm2 = generate_preset_pass_manager(
optimization_level=2, backend=backend, seed_transpiler=777
)
circ0 = pm0.run(ghz_circ)
circ2 = pm2.run(ghz_circ)
print("optimization_level=0:")
display(circ0.draw("mpl", idle_wires=False, fold=-1))
print("optimization_level=2:")
display(circ2.draw("mpl", idle_wires=False, fold=-1))
optimization_level=0:

Output of the previous code cell

optimization_level=2:

Output of the previous code cell

2.2 แบบฝึกหัด

ลอง optimization_level=1 ด้วย แล้วเปรียบเทียบ Circuit ที่ได้กับสองตัวข้างบน ลองทำโดยแก้ไขโค้ดด้านบน

วิธีแก้:

pm1 = generate_preset_pass_manager(
optimization_level=1, backend=backend, seed_transpiler=777
)
circ1 = pm1.run(ghz_circ)
print("optimization_level=1:")
display(circ1.draw("mpl", idle_wires=False, fold=-1))
optimization_level=1:

Output of the previous code cell

รันบน fake backend (การจำลองแบบมีสัญญาณรบกวน) ดูภาคผนวก 1 สำหรับวิธีรันบน Backend จริง

# run the circuits on the fake backend (noisy simulator)
sampler = Sampler(backend=backend)
job = sampler.run([circ0, circ2], shots=10000)
print(f"Job ID: {job.job_id()}")
Job ID: 93a4ac70-e3ea-44ad-aea9-5045840c9076
# get results
result = job.result()
unoptimized_result = result[0].data.meas.get_counts()
optimized_result = result[1].data.meas.get_counts()
from qiskit.visualization import plot_histogram

# plot
sim_result = {"0" * 5: 0.5, "1" * 5: 0.5}
plot_histogram(
[result for result in [sim_result, unoptimized_result, optimized_result]],
bar_labels=False,
legend=[
"ideal",
"no optimization",
"with optimization",
],
)

Output of the previous code cell

3. การสังเคราะห์ Circuit มีความสำคัญ

ต่อไปเราเปรียบเทียบผลลัพธ์ของการรัน Circuit เตรียมสถานะ GHZ 5-Qubit (12(00000+11111)\frac{1}{\sqrt{2}} \left( |00000\rangle + |11111\rangle \right)) สองแบบที่สังเคราะห์ต่างกัน

# Original GHZ circuit (naive synthesis)
ghz_circ.draw("mpl")

Output of the previous code cell

# A cleverly-synthesized GHZ circuit
ghz_circ2 = QuantumCircuit(5)
ghz_circ2.h(2)
ghz_circ2.cx(2, 1)
ghz_circ2.cx(2, 3)
ghz_circ2.cx(1, 0)
ghz_circ2.cx(3, 4)
ghz_circ2.measure_all()
ghz_circ2.draw("mpl")

Output of the previous code cell

# transpile both with the same optimization level 2
circ_org = pm2.run(ghz_circ)
circ_new = pm2.run(ghz_circ2)
print("original synthesis:")
display(circ_org.draw("mpl", idle_wires=False, fold=-1))
print("new synthesis:")
display(circ_new.draw("mpl", idle_wires=False, fold=-1))
original synthesis:

Output of the previous code cell

new synthesis:

Output of the previous code cell

การสังเคราะห์แบบใหม่ให้ Circuit ที่ตื้นกว่า ทำไม?

เพราะ Circuit ใหม่สามารถวางบน Qubit ที่เชื่อมต่อแบบเส้นตรงได้ ดังนั้นบนกราฟการเชื่อมต่อ heavy-hexagon ของ IBM® Brisbane ก็เช่นกัน ในขณะที่ Circuit เดิมต้องการการเชื่อมต่อแบบดาว (โหนดที่มีดีกรี 4) และด้วยเหตุนี้จึงไม่สามารถวางบนกราฟการเชื่อมต่อ heavy-hex ซึ่งมีโหนดที่มีดีกรีมากที่สุด 3 ได้ ผลคือ Circuit เดิมต้องมีการจัดเส้นทาง Qubit ที่เพิ่ม SWAP Gate ทำให้จำนวน Gate เพิ่มขึ้น

สิ่งที่เราทำใน Circuit ใหม่สามารถมองได้ว่าเป็นการสังเคราะห์ Circuit แบบ "คำนึงถึงข้อจำกัดการเชื่อมต่อ" ด้วยตนเอง กล่าวอีกนัยหนึ่งคือ การแก้ปัญหาการสังเคราะห์ Circuit และการแมป Circuit พร้อมกันด้วยตนเอง

# run the circuits
sampler = Sampler(backend=backend)
job = sampler.run([circ_org, circ_new], shots=10000)
print(f"Job ID: {job.job_id()}")
Job ID: 19d635b0-4d8b-44c2-a76e-49e4b9078b1b
# get results
result = job.result()
synthesis_org_result = result[0].data.meas.get_counts()
synthesis_new_result = result[1].data.meas.get_counts()
# plot
sim_result = {"0" * 5: 0.5, "1" * 5: 0.5}
plot_histogram(
[
result
for result in [
sim_result,
unoptimized_result,
synthesis_org_result,
synthesis_new_result,
]
],
bar_labels=False,
legend=[
"ideal",
"no optimization",
"synthesis_org",
"synthesis_new",
],
)

Output of the previous code cell

โดยทั่วไป การสังเคราะห์ Circuit ขึ้นอยู่กับแอปพลิเคชันและยากเกินไปสำหรับซอฟต์แวร์ที่จะครอบคลุมแอปพลิเคชันที่เป็นไปได้ทั้งหมด Qiskit Transpiler ไม่มีฟังก์ชันสำหรับสังเคราะห์ Circuit เตรียมสถานะ GHZ ในกรณีเช่นนี้ การสังเคราะห์ Circuit ด้วยตนเองตามที่แสดงไว้ข้างต้นเป็นสิ่งที่ควรพิจารณา ในส่วนนี้ เราจะเจาะลึกรายละเอียดว่า Qiskit Transpiler ทำงานอย่างไรโดยใช้ Circuit ตัวอย่างต่อไปนี้

# Build a toy example circuit
from math import pi
import itertools
from qiskit.circuit import QuantumCircuit
from qiskit.circuit.library import excitation_preserving

circuit = QuantumCircuit(4, name="Example circuit")
circuit.append(excitation_preserving(4, reps=1, flatten=True), range(4))
circuit.measure_all()

value_cycle = itertools.cycle([0, pi / 4, pi / 2, 3 * pi / 4, pi, 2 * pi])
circuit.assign_parameters(
[x[1] for x in zip(range(len(circuit.parameters)), value_cycle)], inplace=True
)
circuit.draw("mpl")

Output of the previous code cell

3.1 วาดขั้นตอนการ Transpile ทั้งหมดของ Qiskit

เราดู transpiler passes (งาน) สำหรับ optimization_level=1

from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager

# There is no need to read this entire image, but this outputs all the steps in the transpile() call
# for optimization level 1
pm = generate_preset_pass_manager(1, backend, seed_transpiler=42)
pm.draw()

Output of the previous code cell

ขั้นตอนประกอบด้วยหกสเตจ:

print(pm.stages)
('init', 'layout', 'routing', 'translation', 'optimization', 'scheduling')

3.2 วาดสเตจแต่ละอัน

ก่อนอื่น ลองวาดงาน (transpiler passes) ทั้งหมดที่ทำในสเตจ init

pm.init.draw()

Output of the previous code cell

เราสามารถรันแต่ละสเตจแยกกันได้ ลองรันสเตจ init สำหรับ Circuit ของเรา โดยเปิดใช้งาน logger เพื่อดูรายละเอียดของการรัน

import logging

logger = logging.getLogger()
logger.setLevel("INFO")

init_out = pm.init.run(circuit)
init_out.draw("mpl", fold=-1)
INFO:qiskit.passmanager.base_tasks:Pass: UnitarySynthesis - 0.03576 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: HighLevelSynthesis - 0.16618 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: BasisTranslator - 0.07176 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: InverseCancellation - 0.27299 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: ContractIdleWiresInControlFlow - 0.00811 (ms)

Output of the previous code cell

3.3 แบบฝึกหัด

วาด passes ของสเตจ layout และรันสเตจสำหรับ Circuit เอาต์พุตของสเตจ init (init_out) โดยแก้ไขเซลล์ที่ใช้ข้างต้น

วิธีแก้:

display(pm.layout.draw())
layout_out = pm.layout.run(init_out)
layout_out.draw("mpl", idle_wires=False, fold=-1)

Output of the previous code cell

INFO:qiskit.passmanager.base_tasks:Pass: SetLayout - 0.01001 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: TrivialLayout - 0.07129 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: CheckMap - 0.08917 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: VF2Layout - 1.24431 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: BarrierBeforeFinalMeasurements - 0.02599 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: SabreLayout - 5.11169 (ms)

Output of the previous code cell

ทำสิ่งเดียวกันสำหรับสเตจ translation

วิธีแก้:

display(pm.translation.draw())
basis_out = pm.translation.run(layout_out)
basis_out.draw("mpl", idle_wires=False, fold=-1)

Output of the previous code cell

INFO:qiskit.passmanager.base_tasks:Pass: UnitarySynthesis - 0.03386 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: HighLevelSynthesis - 0.02718 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: BasisTranslator - 2.64192 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: CheckGateDirection - 0.02217 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: GateDirection - 0.36502 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: BasisTranslator - 0.64778 (ms)

Output of the previous code cell

หมายเหตุ: สเตจแต่ละอันไม่สามารถรันแยกกันได้เสมอไป (เนื่องจากบางสเตจต้องส่งต่อข้อมูลจากสเตจก่อนหน้า)

3.4 สเตจการปรับแต่ง

สเตจเริ่มต้นสุดท้ายในกระบวนการคือการปรับแต่ง หลังจากที่เราฝัง Circuit สำหรับเป้าหมายแล้ว Circuit ได้ขยายตัวออกไปมาก ส่วนใหญ่เป็นเพราะความไม่มีประสิทธิภาพในความสัมพันธ์ความเท่าเทียมจากการแปลฐานและการแทรก SWAP สเตจการปรับแต่งใช้เพื่อพยายามลดขนาดและความลึกของ Circuit โดยรัน passes หลายชุดในลูป do while จนกว่าจะได้เอาต์พุตที่คงที่

# pm.pre_optimization.draw()
pm.optimization.draw()

Output of the previous code cell

logger = logging.getLogger()
logger.setLevel("INFO")
opt_out = pm.optimization.run(basis_out)
INFO:qiskit.passmanager.base_tasks:Pass: Depth - 0.30112 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: FixedPoint - 0.03195 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: Size - 0.01216 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: FixedPoint - 0.01001 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: Optimize1qGatesDecomposition - 0.63729 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: InverseCancellation - 0.41723 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: ContractIdleWiresInControlFlow - 0.01192 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: GatesInBasis - 0.05484 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: Depth - 0.08583 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: FixedPoint - 0.20599 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: Size - 0.00787 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: FixedPoint - 0.00715 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: Optimize1qGatesDecomposition - 0.16809 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: InverseCancellation - 0.17190 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: ContractIdleWiresInControlFlow - 0.00691 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: GatesInBasis - 0.02408 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: Depth - 0.04935 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: FixedPoint - 0.00525 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: Size - 0.00620 (ms)
INFO:qiskit.passmanager.base_tasks:Pass: FixedPoint - 0.00286 (ms)
opt_out.draw("mpl", idle_wires=False, fold=-1)

Output of the previous code cell

4. ตัวอย่างเชิงลึก

4.1 การปรับแต่งบล็อก Two-qubit โดยใช้การสังเคราะห์ unitary สองคิวบิต

สำหรับระดับ 2 และ 3 เรามี passes เพิ่มเติม (Collect2qBlocks, ConsolidateBlocks, UnitarySynthesis) สำหรับการปรับแต่งมากขึ้น นั่นคือการปรับแต่งบล็อก Two-qubit (เปรียบเทียบขั้นตอนการปรับแต่งสำหรับระดับ 2 กับระดับ 1 ข้างบน)

การปรับแต่งบล็อก Two-qubit ประกอบด้วยสองขั้นตอน: การรวบรวมและรวมบล็อก 2-qubit และการสังเคราะห์เมทริกซ์ unitary 2-qubit

pm2 = generate_preset_pass_manager(2, backend, seed_transpiler=42)
pm2.optimization.draw()

Output of the previous code cell

from qiskit.transpiler import PassManager
from qiskit.transpiler.passes import (
Collect2qBlocks,
ConsolidateBlocks,
UnitarySynthesis,
)

# Collect 2q blocks and consolidate to unitary when we expect that we can reduce the 2q gate count for that unitary
consolidate_pm = PassManager(
[
Collect2qBlocks(),
ConsolidateBlocks(target=backend.target),
]
)
display(basis_out.draw("mpl", idle_wires=False, fold=-1))

consolidated = consolidate_pm.run(basis_out)
consolidated.draw("mpl", idle_wires=False, fold=-1)

Output of the previous code cell

Output of the previous code cell

# Synthesize unitaries
UnitarySynthesis(target=backend.target)(consolidated).draw(
"mpl", idle_wires=False, fold=-1
)

Output of the previous code cell

logger.setLevel("WARNING")

เราเห็นในพาร์ต 2 ว่าขั้นตอนการคอมไพล์ควอนตัมจริงนั้นไม่ได้เรียบง่ายและประกอบด้วย passes (งาน) หลายอย่าง ส่วนใหญ่เป็นเพราะวิศวกรรมซอฟต์แวร์ที่จำเป็นเพื่อให้มั่นใจในประสิทธิภาพสำหรับ Circuit แอปพลิเคชันที่หลากหลายและความสามารถในการบำรุงรักษาซอฟต์แวร์ Qiskit Transpiler จะทำงานได้ดีในกรณีส่วนใหญ่ แต่ถ้าคุณเห็นว่า Circuit ของคุณไม่ได้รับการปรับแต่งอย่างดีโดย Qiskit Transpiler นั่นอาจเป็นโอกาสที่ดีในการวิจัยการปรับแต่ง Circuit เฉพาะแอปพลิเคชันของคุณเองตามที่แสดงในพาร์ต 1 เทคโนโลยี Transpiler กำลังพัฒนา ยินดีต้อนรับการมีส่วนร่วมด้าน R&D ของคุณ

from qiskit.circuit import QuantumCircuit
from qiskit_ibm_runtime import QiskitRuntimeService, Sampler
service = QiskitRuntimeService()
backend = service.backend("ibm_brisbane")
sampler = Sampler(backend)
circ = QuantumCircuit(3)
circ.ccx(0, 1, 2)
circ.measure_all()
circ.draw("mpl")

Output of the previous code cell

sampler.run([circ])  # IBMInputValueError will be raised

4.2 การปรับแต่ง Circuit มีความสำคัญ

เราเปรียบเทียบผลลัพธ์ของการรัน Circuit เตรียมสถานะ GHZ 5-Qubit (12(00000+11111)\frac{1}{\sqrt{2}} \left( |00000\rangle + |11111\rangle \right)) แบบมีและไม่มีการปรับแต่ง

from qiskit.circuit import QuantumCircuit
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService, Sampler
service = QiskitRuntimeService()
# backend = service.backend('ibm_brisbane')
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=127
) # Eagle
backend

เราเริ่มต้นด้วยการใช้ GHZ Circuit ที่สังเคราะห์แบบง่าย ๆ ดังนี้

num_qubits = 5

ghz_circ = QuantumCircuit(num_qubits)
ghz_circ.h(0)
[ghz_circ.cx(0, i) for i in range(1, num_qubits)]
ghz_circ.measure_all()
ghz_circ.draw("mpl")

Output of the previous code cell

เราทำการ Transpile Circuit โดยไม่มีการปรับแต่ง (optimization_level=0) และมีการปรับแต่ง (optimization_level=2) ดังที่เห็น มีความแตกต่างอย่างมากในความยาวของ Circuit ที่ผ่านการ Transpile แล้ว

pm0 = generate_preset_pass_manager(
optimization_level=0, backend=backend, seed_transpiler=777
)
pm2 = generate_preset_pass_manager(
optimization_level=2, backend=backend, seed_transpiler=777
)
circ0 = pm0.run(ghz_circ)
circ2 = pm2.run(ghz_circ)
print("optimization_level=0:")
display(circ0.draw("mpl", idle_wires=False, fold=-1))
print("optimization_level=2:")
display(circ2.draw("mpl", idle_wires=False, fold=-1))
optimization_level=0:

Output of the previous code cell

optimization_level=2:

Output of the previous code cell

# run the circuits
sampler = Sampler(backend)
job = sampler.run([circ0, circ2], shots=10000)
job_id = job.job_id()
print(f"Job ID: {job_id}")
Job ID: d13rnnemya70008ek1zg
# REPLACE WITH YOUR OWN JOB IDS
job = service.job(job_id)
# get results
result = job.result()
unoptimized_result = result[0].data.meas.get_counts()
optimized_result = result[1].data.meas.get_counts()
from qiskit.visualization import plot_histogram

# plot
sim_result = {"0" * 5: 0.5, "1" * 5: 0.5}
plot_histogram(
[result for result in [sim_result, unoptimized_result, optimized_result]],
bar_labels=False,
legend=[
"ideal",
"no optimization",
"with optimization",
],
)

Output of the previous code cell

4.3 การสังเคราะห์ Circuit มีความสำคัญ

ต่อไปเราเปรียบเทียบผลลัพธ์ของการรัน Circuit เตรียมสถานะ GHZ 5-Qubit (12(00000+11111)\frac{1}{\sqrt{2}} \left( |00000\rangle + |11111\rangle \right)) สองแบบที่สังเคราะห์ต่างกัน

# Original GHZ circuit (naive synthesis)
ghz_circ.draw("mpl")

Output of the previous code cell

# A better GHZ circuit (smarter synthesis), you learned in a previous lecture
ghz_circ2 = QuantumCircuit(5)
ghz_circ2.h(2)
ghz_circ2.cx(2, 1)
ghz_circ2.cx(2, 3)
ghz_circ2.cx(1, 0)
ghz_circ2.cx(3, 4)
ghz_circ2.measure_all()
ghz_circ2.draw("mpl")

Output of the previous code cell

circ_org = pm2.run(ghz_circ)
circ_new = pm2.run(ghz_circ2)
print("original synthesis:")
display(circ_org.draw("mpl", idle_wires=False, fold=-1))
print("new synthesis:")
display(circ_new.draw("mpl", idle_wires=False, fold=-1))
original synthesis:

Output of the previous code cell

new synthesis:

Output of the previous code cell

# run the circuits
sampler = Sampler(backend)
job = sampler.run([circ_org, circ_new], shots=10000)
job_id = job.job_id()
print(f"Job ID: {job_id}")
Job ID: d13rp283grvg008j12fg
# REPLACE WITH YOUR OWN JOB IDS
job = service.job(job_id)
# get results
result = job.result()
synthesis_org_result = result[0].data.meas.get_counts()
synthesis_new_result = result[1].data.meas.get_counts()
# plot
sim_result = {"0" * 5: 0.5, "1" * 5: 0.5}
plot_histogram(
[result for result in [sim_result, synthesis_org_result, synthesis_new_result]],
bar_labels=False,
legend=[
"ideal",
"synthesis_org",
"synthesis_new",
],
)

Output of the previous code cell

4.4 การแยกย่อย Gate 1-qubit ทั่วไป

from qiskit import QuantumCircuit, transpile
from qiskit.circuit import Parameter
from qiskit.circuit.library.standard_gates import UGate

phi, theta, lam = Parameter("φ"), Parameter("θ"), Parameter("λ")
qc = QuantumCircuit(1)
qc.append(UGate(theta, phi, lam), [0])
qc.draw(output="mpl")

Output of the previous code cell

transpile(qc, basis_gates=["rz", "sx"]).draw(output="mpl")

Output of the previous code cell

4.5 การปรับแต่งบล็อก One-qubit

from qiskit import QuantumCircuit

qc = QuantumCircuit(1)
qc.x(0)
qc.y(0)
qc.z(0)
qc.rx(1.23, 0)
qc.ry(1.23, 0)
qc.rz(1.23, 0)
qc.h(0)
qc.s(0)
qc.t(0)
qc.sx(0)
qc.sdg(0)
qc.tdg(0)
qc.draw(output="mpl")

Output of the previous code cell

from qiskit.quantum_info import Operator

Operator(qc)
Operator([[ 0.45292511-0.57266982j, -0.66852684-0.14135058j],
[ 0.14135058+0.66852684j, -0.57266982+0.45292511j]],
input_dims=(2,), output_dims=(2,))
from qiskit import transpile

qc_opt = transpile(qc, basis_gates=["rz", "sx"])
qc_opt.draw(output="mpl")

Output of the previous code cell

Operator(qc_opt)
Operator([[ 0.45292511-0.57266982j, -0.66852684-0.14135058j],
[ 0.14135058+0.66852684j, -0.57266982+0.45292511j]],
input_dims=(2,), output_dims=(2,))
Operator(qc).equiv(Operator(qc_opt))
True

4.6 การแยกย่อย Toffoli

qc = QuantumCircuit(3)
qc.ccx(0, 1, 2)
qc.draw(output="mpl")

Output of the previous code cell

from qiskit import QuantumCircuit, transpile

qc = QuantumCircuit(3)
qc.ccx(0, 1, 2)
qc = transpile(qc, basis_gates=["rz", "sx", "cx"])
qc.draw(output="mpl")

Output of the previous code cell

4.7 การแยกย่อย CU gate

from qiskit.circuit.library.standard_gates import CUGate

phi, theta, lam, gamma = Parameter("φ"), Parameter("θ"), Parameter("λ"), Parameter("γ")
qc = QuantumCircuit(2)
# qc.cu(theta, phi, lam, gamma, 0, 1)
qc.append(CUGate(theta, phi, lam, gamma), [0, 1])
qc.draw(output="mpl")

Output of the previous code cell

from qiskit.circuit.library.standard_gates import CUGate

phi, theta, lam, gamma = Parameter("φ"), Parameter("θ"), Parameter("λ"), Parameter("γ")
qc = QuantumCircuit(2)
qc.append(CUGate(theta, phi, lam, gamma), [0, 1])
qc = transpile(qc, basis_gates=["rz", "sx", "cx"])
qc.draw(output="mpl")

Output of the previous code cell

4.8 CX, ECR, CZ เท่ากันจนถึง local Cliffords

โปรดทราบว่า HH(Hadamard), SS(π/2\pi/2 Z-rotation), SS^\dagger(π/2-\pi/2 Z-rotation), XX(Pauli X) ล้วนเป็น Clifford gates

qc = QuantumCircuit(2)
qc.cx(0, 1)
qc.draw(output="mpl", style="bw")

Output of the previous code cell

qc = QuantumCircuit(2)
qc.cx(0, 1)
transpile(qc, basis_gates=["x", "s", "h", "sdg", "ecr"]).draw(output="mpl", style="bw")

Output of the previous code cell

qc = QuantumCircuit(2)
qc.cx(0, 1)
transpile(qc, basis_gates=["h", "cz"]).draw(output="mpl", style="bw")

Output of the previous code cell

ใช้ basis gates 1q ของ IBM backend คือ "rz", "sx" และ "x"

qc = QuantumCircuit(2)
qc.cx(0, 1)
transpile(qc, basis_gates=["rz", "sx", "x", "ecr"]).draw(output="mpl", style="bw")

Output of the previous code cell

qc = QuantumCircuit(2)
qc.cx(0, 1)
transpile(qc, basis_gates=["rz", "sx", "x", "cz"]).draw(output="mpl", style="bw")

Output of the previous code cell

# Check Qiskit version
import qiskit

qiskit.__version__
'2.0.2'
Source: IBM Quantum docs — updated 27 เม.ย. 2569
English version on doQumentation — updated 7 พ.ค. 2569
This translation based on the English version of 27 มี.ค. 2569