Métodos de compilação para circuitos de simulação Hamiltoniana
Uso estimado de QPU: nenhuma execução foi feita neste tutorial porque ele está focado no processo de transpilação.
Contexto
A compilação de circuitos quânticos é uma etapa crucial no fluxo de trabalho da computação quântica. Ela envolve transformar um algoritmo quântico de alto nível em um circuito quântico físico que adere às restrições do hardware quântico alvo. Uma compilação eficaz pode impactar significativamente o desempenho de algoritmos quânticos ao reduzir a profundidade do circuito, contagem de portas e tempo de execução. Este tutorial explora três abordagens distintas para compilação de circuitos quânticos no Qiskit, mostrando seus pontos fortes e aplicações através de exemplos práticos.
O objetivo deste tutorial é ensinar os usuários como aplicar e avaliar três métodos de compilação no Qiskit: o transpiler SABRE, o transpiler alimentado por IA e o plugin Rustiq. Os usuários aprenderão como usar cada método efetivamente e como avaliar seu desempenho em diferentes circuitos quânticos. Ao final deste tutorial, os usuários serão capazes de escolher e adaptar estratégias de compilação com base em objetivos de otimização específicos, como reduzir a profundidade do circuito, minimizar a contagem de portas ou melhorar o tempo de execução.
O que você aprenderá
- Como usar o transpiler do Qiskit com SABRE para otimização de layout e roteamento.
- Como aproveitar o transpiler de IA para otimização avançada e automatizada de circuitos.
- Como empregar o plugin Rustiq para circuitos que requerem síntese precisa de operações, particularmente em tarefas de simulação Hamiltoniana.
Este tutorial usa três circuitos de exemplo seguindo o fluxo de trabalho de padrões do Qiskit para ilustrar o desempenho de cada método de compilação. Ao final deste tutorial, os usuários estarão equipados para escolher a estratégia de compilação apropriada com base em seus requisitos e restrições específicas.
Visão geral dos métodos de compilação
1. Transpiler do Qiskit com SABRE
O transpiler do Qiskit usa o algoritmo SABRE (SWAP-based BidiREctional heuristic search) para otimizar o layout e roteamento do circuito. O SABRE se concentra em minimizar portas SWAP e seu impacto na profundidade do circuito, ao mesmo tempo que adere às restrições de conectividade do hardware. Este método é altamente versátil e adequado para otimização de circuitos de uso geral, fornecendo um equilíbrio entre desempenho e tempo de computação. Para aproveitar as melhorias mais recentes no SABRE, detalhadas em [1], você pode aumentar o número de tentativas (por exemplo, layout_trials=400, swap_trials=400). Para os propósitos deste tutorial, usaremos os valores padrão para o número de tentativas, a fim de comparar com o transpiler padrão do Qiskit. As vantagens e exploração de parâmetros do SABRE são abordadas em um tutorial detalhado separado.
2. Transpiler de IA
O transpiler alimentado por IA no Qiskit usa aprendizado de máquina para prever estratégias ótimas de transpilação, analisando padrões na estrutura do circuito e restrições de hardware para selecionar a melhor sequência de otimizações para uma entrada específica. Este método é particularmente eficaz para circuitos quânticos de grande escala, oferecendo um alto grau de automação e adaptabilidade a diversos tipos de problemas. Além da otimização geral de circuitos, o transpiler de IA pode ser usado com o passe AIPauliNetworkSynthesis, que tem como alvo circuitos de rede Pauli — blocos compostos de portas H, S, SX, CX, RX, RY e RZ — e aplica uma abordagem de síntese baseada em aprendizado por reforço. Para mais informações sobre o transpiler de IA e suas estratégias de síntese, consulte [2] e [3].
3. Plugin Rustiq
O plugin Rustiq introduz técnicas avançadas de síntese especificamente para operações PauliEvolutionGate, que representam rotações de Pauli comumente usadas em dinâmicas trotterizadas. Este plugin é valioso para circuitos que implementam simulação Hamiltoniana, como aqueles usados em problemas de química quântica e física, onde rotações de Pauli precisas são essenciais para simular Hamiltonianos de problema efetivamente. O Rustiq oferece síntese de circuito precisa e de baixa profundidade para essas operações especializadas. Para mais detalhes sobre a implementação e desempenho do Rustiq, consulte [4].
Ao explorar esses métodos de compilação em profundidade, este tutorial fornece aos usuários as ferramentas para aprimorar o desempenho de seus circuitos quânticos, pavimentando o caminho para computações quânticas mais eficientes e práticas.
Requisitos
Antes de começar este tutorial, certifique-se de ter o seguinte instalado:
- Qiskit SDK v1.3 ou posterior, com suporte a visualização
- Qiskit Runtime v0.28 ou posterior (
pip install qiskit-ibm-runtime) - Qiskit IBM Transpiler (
pip install qiskit-ibm-transpiler) - Modo local do Qiskit AI Transpiler (
pip install qiskit_ibm_ai_local_transpiler) - Biblioteca de grafos Networkx (
pip install networkx)
Configuração
# Added by doQumentation — required packages for this notebook
!pip install -q IPython matplotlib numpy pandas qiskit qiskit-ibm-runtime qiskit-ibm-transpiler requests
from qiskit.circuit import QuantumCircuit
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit.circuit.library import (
efficient_su2,
PauliEvolutionGate,
)
from qiskit_ibm_transpiler import generate_ai_pass_manager
from qiskit.quantum_info import SparsePauliOp
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit.transpiler.passes.synthesis.high_level_synthesis import HLSConfig
from collections import Counter
from IPython.display import display
import time
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import json
import requests
import logging
# Suppress noisy loggers
logging.getLogger(
"qiskit_ibm_transpiler.wrappers.ai_local_synthesis"
).setLevel(logging.ERROR)
seed = 42 # Seed for reproducibility
Parte 1: Circuito SU2 Eficiente
Passo 1: Mapear entradas clássicas para um problema quântico
Nesta seção, exploramos o circuito efficient_su2, um ansatz eficiente em hardware comumente usado em algoritmos quânticos variacionais (como VQE) e tarefas de aprendizado de máquina quântico. O circuito consiste em camadas alternadas de rotações de um único qubit e portas de emaranhamento organizadas em um padrão circular, projetado para explorar o espaço de estados quânticos efetivamente, mantendo uma profundidade gerenciável.
Começaremos construindo um circuito efficient_su2 para demonstrar como comparar diferentes métodos de compilação. Após a Parte 1, expandiremos nossa análise para um conjunto maior de circuitos, permitindo um benchmark abrangente para avaliar o desempenho de várias técnicas de compilação.
qubit_size = list(range(10, 101, 10))
qc_su2_list = [
efficient_su2(n, entanglement="circular", reps=1)
.decompose()
.copy(name=f"SU2_{n}")
for n in qubit_size
]
# Draw the first circuit
qc_su2_list[0].draw(output="mpl")
Passo 2: Otimizar o problema para execução em hardware quântico
Este passo é o foco principal do tutorial. Aqui, pretendemos otimizar circuitos quânticos para execução eficiente em hardware quântico real. Nosso objetivo principal é reduzir a profundidade do circuito e a contagem de portas, que são fatores-chave para melhorar a fidelidade de execução e mitigar o ruído do hardware.
- Transpiler SABRE: Usa o transpiler padrão do Qiskit com o algoritmo de layout e roteamento SABRE.
- Transpiler de IA (modo local): O transpiler alimentado por IA padrão usando inferência local e a estratégia de síntese padrão.
- Plugin Rustiq: Um plugin de transpiler projetado para compilação de baixa profundidade adaptado a tarefas de simulação Hamiltoniana.
O objetivo deste passo é comparar os resultados desses métodos em termos da profundidade do circuito transpilado e contagem de portas. Outra métrica importante que consideramos é o tempo de execução da transpilação. Ao analisar essas métricas, podemos avaliar os pontos fortes relativos de cada método e determinar qual produz o circuito mais eficiente para execução no hardware selecionado.
Nota: Para o exemplo inicial do circuito SU2, compararemos apenas o transpiler SABRE ao transpiler de IA padrão. No entanto, no benchmark subsequente usando circuitos Hamlib, compararemos todos os três métodos de transpilação.
# QiskitRuntimeService.save_account(channel="ibm_quantum_platform", token="<YOUR-API-KEY>", overwrite=True, set_as_default=True)
service = QiskitRuntimeService(channel="ibm_quantum_platform")
backend = service.backend("ibm_torino")
print(f"Using backend: {backend}")
qiskit_runtime_service._get_crn_from_instance_name:WARNING:2025-07-30 21:46:30,843: Multiple instances found. Using all matching instances.
Using backend: <IBMBackend('ibm_torino')>
Transpiler do Qiskit com SABRE:
pm_sabre = generate_preset_pass_manager(
optimization_level=3, backend=backend, seed_transpiler=seed
)
Transpiler de IA:
# Standard AI transpiler pass manager, using the local mode
pm_ai = generate_ai_pass_manager(
backend=backend, optimization_level=3, ai_optimization_level=3
)
Plugin Rustiq:
hls_config = HLSConfig(
PauliEvolution=[
(
"rustiq",
{
"nshuffles": 400,
"upto_phase": True,
"fix_clifford": True,
"preserve_order": False,
"metric": "depth",
},
)
]
)
pm_rustiq = generate_preset_pass_manager(
optimization_level=3,
backend=backend,
hls_config=hls_config,
seed_transpiler=seed,
)
Transpilar e capturar métricas
Para comparar o desempenho dos métodos de compilação, definimos uma função que transpila o circuito de entrada e captura métricas relevantes de maneira consistente. Isso inclui a profundidade total do circuito, contagem geral de portas e tempo de transpilação.
Além dessas métricas padrão, também registramos a profundidade de portas de 2 qubits, que é uma métrica particularmente importante para avaliar a execução em hardware quântico. Ao contrário da profundidade total, que inclui todas as portas, a profundidade de 2 qubits reflete mais precisamente a duração real de execução do circuito no hardware. Isso ocorre porque as portas de 2 qubits normalmente dominam o orçamento de tempo e erro na maioria dos dispositivos quânticos. Como tal, minimizar a profundidade de 2 qubits é crítico para melhorar a fidelidade e reduzir os efeitos de decoerência durante a execução.
Usaremos esta função para analisar o desempenho dos diferentes métodos de compilação em múltiplos circuitos.
def capture_transpilation_metrics(
results, pass_manager, circuits, method_name
):
"""
Capture transpilation metrics for a list of circuits and stores the results in a DataFrame.
Args:
results (pd.DataFrame): DataFrame to store the results.
pass_manager: Pass manager used for transpilation.
circuits (list): List of quantum circuits to transpile.
method_name (str): Name of the transpilation method.
Returns:
list: List of transpiled circuits.
"""
transpiled_circuits = []
for i, qc in enumerate(circuits):
# Transpile the circuit
start_time = time.time()
transpiled_qc = pass_manager.run(qc)
end_time = time.time()
# Needed for AI transpiler to be consistent with other methods
transpiled_qc = transpiled_qc.decompose(gates_to_decompose=["swap"])
# Collect metrics
transpilation_time = end_time - start_time
circuit_depth = transpiled_qc.depth(
lambda x: x.operation.num_qubits == 2
)
circuit_size = transpiled_qc.size()
# Append results to DataFrame
results.loc[len(results)] = {
"method": method_name,
"qc_name": qc.name,
"qc_index": i,
"num_qubits": qc.num_qubits,
"ops": transpiled_qc.count_ops(),
"depth": circuit_depth,
"size": circuit_size,
"runtime": transpilation_time,
}
transpiled_circuits.append(transpiled_qc)
print(
f"Transpiled circuit index {i} ({qc.name}) in {transpilation_time:.2f} seconds with method {method_name}, "
f"depth {circuit_depth}, and size {circuit_size}."
)
return transpiled_circuits
results_su2 = pd.DataFrame(
columns=[
"method",
"qc_name",
"qc_index",
"num_qubits",
"ops",
"depth",
"size",
"runtime",
]
)
tqc_sabre = capture_transpilation_metrics(
results_su2, pm_sabre, qc_su2_list, "sabre"
)
tqc_ai = capture_transpilation_metrics(results_su2, pm_ai, qc_su2_list, "ai")
Transpiled circuit index 0 (SU2_10) in 0.06 seconds with method sabre, depth 13, and size 167.
Transpiled circuit index 1 (SU2_20) in 0.24 seconds with method sabre, depth 20, and size 299.
Transpiled circuit index 2 (SU2_30) in 10.72 seconds with method sabre, depth 72, and size 627.
Transpiled circuit index 3 (SU2_40) in 16.16 seconds with method sabre, depth 40, and size 599.
Transpiled circuit index 4 (SU2_50) in 76.89 seconds with method sabre, depth 77, and size 855.
Transpiled circuit index 5 (SU2_60) in 86.12 seconds with method sabre, depth 60, and size 899.
Transpiled circuit index 6 (SU2_70) in 94.46 seconds with method sabre, depth 79, and size 1085.
Transpiled circuit index 7 (SU2_80) in 69.05 seconds with method sabre, depth 80, and size 1199.
Transpiled circuit index 8 (SU2_90) in 88.25 seconds with method sabre, depth 105, and size 1420.
Transpiled circuit index 9 (SU2_100) in 83.80 seconds with method sabre, depth 100, and size 1499.
Transpiled circuit index 0 (SU2_10) in 0.17 seconds with method ai, depth 10, and size 168.
Transpiled circuit index 1 (SU2_20) in 0.29 seconds with method ai, depth 20, and size 299.
Transpiled circuit index 2 (SU2_30) in 13.56 seconds with method ai, depth 36, and size 548.
Transpiled circuit index 3 (SU2_40) in 15.95 seconds with method ai, depth 40, and size 599.
Transpiled circuit index 4 (SU2_50) in 80.70 seconds with method ai, depth 54, and size 823.
Transpiled circuit index 5 (SU2_60) in 75.99 seconds with method ai, depth 60, and size 899.
Transpiled circuit index 6 (SU2_70) in 64.96 seconds with method ai, depth 74, and size 1087.
Transpiled circuit index 7 (SU2_80) in 68.25 seconds with method ai, depth 80, and size 1199.
Transpiled circuit index 8 (SU2_90) in 75.07 seconds with method ai, depth 90, and size 1404.
Transpiled circuit index 9 (SU2_100) in 63.97 seconds with method ai, depth 100, and size 1499.
Exibir resultados transpilados de um dos circuitos.
print("Sabre transpilation")
display(tqc_sabre[0].draw("mpl", fold=-1, idle_wires=False))
print("AI transpilation")
display(tqc_ai[0].draw("mpl", fold=-1, idle_wires=False))
Sabre transpilation

AI transpilation

Tabela de resultados:
summary_su2 = (
results_su2.groupby("method")[["depth", "size", "runtime"]]
.mean()
.round(2)
)
print(summary_su2)
results_su2
depth size runtime
method
ai 56.4 852.5 45.89
sabre 64.6 864.9 52.57
method qc_name qc_index num_qubits ops \
0 sabre SU2_10 0 10 {'rz': 81, 'sx': 70, 'cz': 16}
1 sabre SU2_20 1 20 {'rz': 160, 'sx': 119, 'cz': 20}
2 sabre SU2_30 2 30 {'sx': 295, 'rz': 242, 'cz': 90}
3 sabre SU2_40 3 40 {'rz': 320, 'sx': 239, 'cz': 40}
4 sabre SU2_50 4 50 {'rz': 402, 'sx': 367, 'cz': 86}
5 sabre SU2_60 5 60 {'rz': 480, 'sx': 359, 'cz': 60}
6 sabre SU2_70 6 70 {'rz': 562, 'sx': 441, 'cz': 82}
7 sabre SU2_80 7 80 {'rz': 640, 'sx': 479, 'cz': 80}
8 sabre SU2_90 8 90 {'rz': 721, 'sx': 585, 'cz': 114}
9 sabre SU2_100 9 100 {'rz': 800, 'sx': 599, 'cz': 100}
10 ai SU2_10 0 10 {'rz': 81, 'sx': 71, 'cz': 16}
11 ai SU2_20 1 20 {'rz': 160, 'sx': 119, 'cz': 20}
12 ai SU2_30 2 30 {'sx': 243, 'rz': 242, 'cz': 63}
13 ai SU2_40 3 40 {'rz': 320, 'sx': 239, 'cz': 40}
14 ai SU2_50 4 50 {'rz': 403, 'sx': 346, 'cz': 74}
15 ai SU2_60 5 60 {'rz': 480, 'sx': 359, 'cz': 60}
16 ai SU2_70 6 70 {'rz': 563, 'sx': 442, 'cz': 82}
17 ai SU2_80 7 80 {'rz': 640, 'sx': 479, 'cz': 80}
18 ai SU2_90 8 90 {'rz': 721, 'sx': 575, 'cz': 108}
19 ai SU2_100 9 100 {'rz': 800, 'sx': 599, 'cz': 100}
depth size runtime
0 13 167 0.058845
1 20 299 0.238217
2 72 627 10.723922
3 40 599 16.159262
4 77 855 76.886604
5 60 899 86.118255
6 79 1085 94.458287
7 80 1199 69.048184
8 105 1420 88.254809
9 100 1499 83.795482
10 10 168 0.171532
11 20 299 0.291691
12 36 548 13.555931
13 40 599 15.952733
14 54 823 80.702141
15 60 899 75.993404
16 74 1087 64.960162
17 80 1199 68.253280
18 90 1404 75.072412
19 100 1499 63.967446
Gráfico de resultados
Como definimos uma função para capturar métricas de forma consistente, também definiremos uma para representar graficamente as métricas. Aqui, plotaremos a profundidade de dois qubits, contagem de portas e tempo de execução para cada método de compilação nos circuitos.
def plot_transpilation_metrics(results, overall_title, x_axis="qc_index"):
"""
Plots transpilation metrics (depth, size, runtime) for different transpilation methods.
Parameters:
results (DataFrame): Data containing columns ['num_qubits', 'method', 'depth', 'size', 'runtime']
overall_title (str): The title of the overall figure.
x_axis (str): The x-axis label, either 'num_qubits' or 'qc_index'.
"""
fig, axs = plt.subplots(1, 3, figsize=(24, 6))
metrics = ["depth", "size", "runtime"]
titles = ["Circuit Depth", "Circuit Size", "Transpilation Runtime"]
y_labels = ["Depth", "Size (Gate Count)", "Runtime (s)"]
methods = results["method"].unique()
colors = plt.colormaps["tab10"]
markers = ["o", "^", "s", "D", "P", "*", "X", "v"]
color_list = [colors(i % colors.N) for i in range(len(methods))]
color_map = {method: color_list[i] for i, method in enumerate(methods)}
marker_map = {
method: markers[i % len(markers)] for i, method in enumerate(methods)
}
jitter_factor = 0.1 # Small x-axis jitter for visibility
handles, labels = [], [] # Unique handles for legend
# Plot each metric
for i, metric in enumerate(metrics):
for method in methods:
method_data = results[results["method"] == method]
# Introduce slight jitter to avoid exact overlap
jitter = np.random.uniform(
-jitter_factor, jitter_factor, len(method_data)
)
scatter = axs[i].scatter(
method_data[x_axis] + jitter,
method_data[metric],
color=color_map[method],
label=method,
marker=marker_map[method],
alpha=0.7,
edgecolors="black",
s=80,
)
if method not in labels:
handles.append(scatter)
labels.append(method)
axs[i].set_title(titles[i])
axs[i].set_xlabel(x_axis)
axs[i].set_ylabel(y_labels[i])
axs[i].grid(axis="y", linestyle="--", alpha=0.7)
axs[i].tick_params(axis="x", rotation=45)
axs[i].set_xticks(sorted(results[x_axis].unique()))
fig.suptitle(overall_title, fontsize=16)
fig.legend(
handles=handles,
labels=labels,
loc="upper right",
bbox_to_anchor=(1.05, 1),
)
plt.tight_layout()
plt.show()
plot_transpilation_metrics(
results_su2, "Transpilation Metrics for SU2 Circuits", x_axis="num_qubits"
)

Análise dos resultados de compilação de circuitos SU2
Neste experimento, comparamos dois métodos de transpilação — o transpilador SABRE do Qiskit e o transpilador com IA — em um conjunto de circuitos efficient_su2. Como esses circuitos não incluem nenhuma operação PauliEvolutionGate, o plugin Rustiq não está incluído nesta comparação.
Em média, o transpilador de IA apresenta melhor desempenho em termos de profundidade do circuito, com uma melhoria superior a 10% em toda a gama de circuitos SU2. Para contagem de portas (tamanho do circuito) e tempo de execução da transpilação, ambos os métodos produzem resultados semelhantes no geral.
No entanto, a inspeção dos pontos de dados individuais revela uma percepção mais profunda:
- Para a maioria dos tamanhos de qubits, tanto SABRE quanto IA produzem resultados quase idênticos, sugerindo que em muitos casos, ambos os métodos convergem para soluções similarmente eficientes.
- Para certos tamanhos de circuito, especificamente em 30, 50, 70 e 90 qubits, o transpilador de IA encontra circuitos significativamente mais rasos do que o SABRE. Isso indica que a abordagem baseada em aprendizado da IA é capaz de descobrir layouts ou caminhos de roteamento mais otimizados em casos onde a heurística SABRE não consegue.
Este comportamento destaca uma conclusão importante:
Embora o SABRE e a IA frequentemente produzam resultados comparáveis, o transpilador de IA pode ocasionalmente descobrir soluções muito melhores, particularmente em termos de profundidade, o que pode levar a desempenho significativamente melhorado no hardware.
Parte 2: Circuito de simulação Hamiltoniana
Passo 1: Investigar circuitos com PauliEvolutionGate
Nesta seção, investigamos circuitos quânticos construídos usando PauliEvolutionGate, que permite simulação eficiente de Hamiltonianos. Analisaremos como diferentes métodos de compilação otimizam esses circuitos em vários Hamiltonianos.
Hamiltonianos usados no benchmark
Os Hamiltonianos usados neste benchmark descrevem interações em pares entre qubits, incluindo termos como , e . Esses Hamiltonianos são comumente usados em química quântica, física da matéria condensada e ciência dos materiais, onde modelam sistemas de partículas interagindo.
Para referência, os usuários podem explorar um conjunto mais amplo de Hamiltonianos neste artigo: Efficient Hamiltonian Simulation on Noisy Quantum Devices.
Fonte do benchmark: Hamlib e Benchpress
Os circuitos usados neste benchmark são extraídos do repositório de benchmark Hamlib, que contém cargas de trabalho realistas de simulação Hamiltoniana.
Esses mesmos circuitos foram previamente avaliados usando Benchpress, um framework de código aberto para avaliar o desempenho de transpilação quântica. Ao usar esse conjunto padronizado de circuitos, podemos comparar diretamente a eficácia de diferentes estratégias de compilação em problemas de simulação representativos.
A simulação Hamiltoniana é uma tarefa fundamental na computação quântica, com aplicações em simulações moleculares, problemas de otimização e física de muitos corpos quânticos. Compreender como diferentes métodos de compilação otimizam esses circuitos pode ajudar os usuários a melhorar a execução prática de tais circuitos em dispositivos quânticos de curto prazo.
# Obtain the Hamiltonian JSON from the benchpress repository
url = "https://raw.githubusercontent.com/Qiskit/benchpress/e7b29ef7be4cc0d70237b8fdc03edbd698908eff/benchpress/hamiltonian/hamlib/100_representative.json"
response = requests.get(url)
response.raise_for_status() # Raise an error if download failed
ham_records = json.loads(response.text)
# Remove circuits that are too large for the backend
ham_records = [
h for h in ham_records if h["ham_qubits"] <= backend.num_qubits
]
# Remove the circuits that are large to save transpilation time
ham_records = sorted(ham_records, key=lambda x: x["ham_terms"])[:35]
qc_ham_list = []
for h in ham_records:
terms = h["ham_hamlib_hamiltonian_terms"]
coeff = h["ham_hamlib_hamiltonian_coefficients"]
num_qubits = h["ham_qubits"]
name = h["ham_problem"]
evo_gate = PauliEvolutionGate(SparsePauliOp(terms, coeff))
qc_ham = QuantumCircuit(num_qubits)
qc_ham.name = name
qc_ham.append(evo_gate, range(num_qubits))
qc_ham_list.append(qc_ham)
print(f"Number of Hamiltonian circuits: {len(qc_ham_list)}")
# Draw the first Hamiltonian circuit
qc_ham_list[0].draw("mpl", fold=-1)
Number of Hamiltonian circuits: 35
Passo 2: Otimizar problema para execução em hardware quântico
Como no exemplo anterior, usaremos o mesmo backend para garantir consistência em nossas comparações. Como os gerenciadores de passos (pm_sabre, pm_ai e pm_rustiq) já foram inicializados, podemos prosseguir diretamente com a transpilação dos circuitos Hamiltonianos usando cada método.
Este passo foca exclusivamente na realização da transpilação e registro das métricas resultantes do circuito, incluindo profundidade, contagem de portas e tempo de execução da transpilação. Ao analisar esses resultados, buscamos determinar a eficiência de cada método de transpilação para este tipo de circuito. Transpilar e capturar métricas:
results_ham = pd.DataFrame(
columns=[
"method",
"qc_name",
"qc_index",
"num_qubits",
"ops",
"depth",
"size",
"runtime",
]
)
tqc_sabre = capture_transpilation_metrics(
results_ham, pm_sabre, qc_ham_list, "sabre"
)
tqc_ai = capture_transpilation_metrics(results_ham, pm_ai, qc_ham_list, "ai")
tqc_rustiq = capture_transpilation_metrics(
results_ham, pm_rustiq, qc_ham_list, "rustiq"
)
Transpiled circuit index 0 (all-vib-o3) in 0.02 seconds with method sabre, depth 6, and size 58.
Transpiled circuit index 1 (all-vib-c2h) in 1.10 seconds with method sabre, depth 2, and size 39.
Transpiled circuit index 2 (all-vib-bh) in 0.01 seconds with method sabre, depth 3, and size 30.
Transpiled circuit index 3 (all-vib-c2h) in 0.03 seconds with method sabre, depth 18, and size 115.
Transpiled circuit index 4 (graph-gnp_k-2) in 0.02 seconds with method sabre, depth 24, and size 129.
Transpiled circuit index 5 (all-vib-fccf) in 0.05 seconds with method sabre, depth 14, and size 134.
Transpiled circuit index 6 (all-vib-hno) in 8.39 seconds with method sabre, depth 6, and size 174.
Transpiled circuit index 7 (all-vib-bhf2) in 3.92 seconds with method sabre, depth 22, and size 220.
Transpiled circuit index 8 (LiH) in 0.03 seconds with method sabre, depth 67, and size 290.
Transpiled circuit index 9 (uf20-ham) in 0.04 seconds with method sabre, depth 50, and size 340.
Transpiled circuit index 10 (all-vib-fccf) in 0.62 seconds with method sabre, depth 30, and size 286.
Transpiled circuit index 11 (all-vib-fccf) in 0.04 seconds with method sabre, depth 67, and size 339.
Transpiled circuit index 12 (all-vib-ch2) in 0.04 seconds with method sabre, depth 87, and size 421.
Transpiled circuit index 13 (tfim) in 0.05 seconds with method sabre, depth 36, and size 222.
Transpiled circuit index 14 (all-vib-cyclo_propene) in 9.51 seconds with method sabre, depth 22, and size 345.
Transpiled circuit index 15 (graph-gnp_k-4) in 0.05 seconds with method sabre, depth 128, and size 704.
Transpiled circuit index 16 (all-vib-hc3h2cn) in 13.83 seconds with method sabre, depth 2, and size 242.
Transpiled circuit index 17 (TSP_Ncity-4) in 0.05 seconds with method sabre, depth 106, and size 609.
Transpiled circuit index 18 (tfim) in 0.29 seconds with method sabre, depth 73, and size 399.
Transpiled circuit index 19 (all-vib-h2co) in 21.97 seconds with method sabre, depth 30, and size 572.
Transpiled circuit index 20 (Be2) in 0.09 seconds with method sabre, depth 324, and size 1555.
Transpiled circuit index 21 (graph-complete_bipart) in 0.12 seconds with method sabre, depth 250, and size 1394.
Transpiled circuit index 22 (all-vib-f2) in 0.07 seconds with method sabre, depth 215, and size 1027.
Transpiled circuit index 23 (all-vib-cyclo_propene) in 41.22 seconds with method sabre, depth 30, and size 1144.
Transpiled circuit index 24 (TSP_Ncity-5) in 1.89 seconds with method sabre, depth 175, and size 1933.
Transpiled circuit index 25 (H2) in 0.32 seconds with method sabre, depth 1237, and size 5502.
Transpiled circuit index 26 (uuf100-ham) in 0.20 seconds with method sabre, depth 385, and size 4303.
Transpiled circuit index 27 (ham-graph-gnp_k-5) in 0.20 seconds with method sabre, depth 311, and size 3654.
Transpiled circuit index 28 (tfim) in 0.15 seconds with method sabre, depth 276, and size 3213.
Transpiled circuit index 29 (uuf100-ham) in 0.21 seconds with method sabre, depth 520, and size 5250.
Transpiled circuit index 30 (flat100-ham) in 0.15 seconds with method sabre, depth 131, and size 3157.
Transpiled circuit index 31 (uf100-ham) in 0.24 seconds with method sabre, depth 624, and size 7378.
Transpiled circuit index 32 (OH) in 0.88 seconds with method sabre, depth 2175, and size 9808.
Transpiled circuit index 33 (HF) in 0.66 seconds with method sabre, depth 2206, and size 9417.
Transpiled circuit index 34 (BH) in 0.89 seconds with method sabre, depth 2177, and size 9802.
Transpiled circuit index 0 (all-vib-o3) in 0.02 seconds with method ai, depth 6, and size 58.
Transpiled circuit index 1 (all-vib-c2h) in 1.11 seconds with method ai, depth 2, and size 39.
Transpiled circuit index 2 (all-vib-bh) in 0.01 seconds with method ai, depth 3, and size 30.
Transpiled circuit index 3 (all-vib-c2h) in 0.11 seconds with method ai, depth 18, and size 94.
Transpiled circuit index 4 (graph-gnp_k-2) in 0.11 seconds with method ai, depth 22, and size 129.
Transpiled circuit index 5 (all-vib-fccf) in 0.06 seconds with method ai, depth 22, and size 177.
Transpiled circuit index 6 (all-vib-hno) in 8.62 seconds with method ai, depth 10, and size 198.
Transpiled circuit index 7 (all-vib-bhf2) in 3.71 seconds with method ai, depth 18, and size 195.
Transpiled circuit index 8 (LiH) in 0.19 seconds with method ai, depth 62, and size 267.
Transpiled circuit index 9 (uf20-ham) in 0.22 seconds with method ai, depth 47, and size 321.
Transpiled circuit index 10 (all-vib-fccf) in 0.71 seconds with method ai, depth 38, and size 369.
Transpiled circuit index 11 (all-vib-fccf) in 0.24 seconds with method ai, depth 65, and size 315.
Transpiled circuit index 12 (all-vib-ch2) in 0.24 seconds with method ai, depth 91, and size 430.
Transpiled circuit index 13 (tfim) in 0.15 seconds with method ai, depth 12, and size 251.
Transpiled circuit index 14 (all-vib-cyclo_propene) in 8.50 seconds with method ai, depth 18, and size 311.
Transpiled circuit index 15 (graph-gnp_k-4) in 0.25 seconds with method ai, depth 117, and size 659.
Transpiled circuit index 16 (all-vib-hc3h2cn) in 16.11 seconds with method ai, depth 2, and size 242.
Transpiled circuit index 17 (TSP_Ncity-4) in 0.39 seconds with method ai, depth 98, and size 564.
Transpiled circuit index 18 (tfim) in 0.38 seconds with method ai, depth 23, and size 437.
Transpiled circuit index 19 (all-vib-h2co) in 24.97 seconds with method ai, depth 38, and size 707.
Transpiled circuit index 20 (Be2) in 1.07 seconds with method ai, depth 293, and size 1392.
Transpiled circuit index 21 (graph-complete_bipart) in 0.61 seconds with method ai, depth 229, and size 1437.
Transpiled circuit index 22 (all-vib-f2) in 0.57 seconds with method ai, depth 178, and size 964.
Transpiled circuit index 23 (all-vib-cyclo_propene) in 50.89 seconds with method ai, depth 34, and size 1425.
Transpiled circuit index 24 (TSP_Ncity-5) in 1.61 seconds with method ai, depth 171, and size 2020.
Transpiled circuit index 25 (H2) in 6.39 seconds with method ai, depth 1148, and size 5208.
Transpiled circuit index 26 (uuf100-ham) in 3.97 seconds with method ai, depth 376, and size 5048.
Transpiled circuit index 27 (ham-graph-gnp_k-5) in 3.54 seconds with method ai, depth 357, and size 4451.
Transpiled circuit index 28 (tfim) in 1.72 seconds with method ai, depth 216, and size 3026.
Transpiled circuit index 29 (uuf100-ham) in 4.45 seconds with method ai, depth 426, and size 5399.
Transpiled circuit index 30 (flat100-ham) in 7.02 seconds with method ai, depth 86, and size 3108.
Transpiled circuit index 31 (uf100-ham) in 12.85 seconds with method ai, depth 623, and size 8354.
Transpiled circuit index 32 (OH) in 15.19 seconds with method ai, depth 2084, and size 9543.
Transpiled circuit index 33 (HF) in 17.51 seconds with method ai, depth 2063, and size 9446.
Transpiled circuit index 34 (BH) in 15.33 seconds with method ai, depth 2094, and size 9730.
Transpiled circuit index 0 (all-vib-o3) in 0.02 seconds with method rustiq, depth 13, and size 83.
Transpiled circuit index 1 (all-vib-c2h) in 1.11 seconds with method rustiq, depth 2, and size 39.
Transpiled circuit index 2 (all-vib-bh) in 0.01 seconds with method rustiq, depth 3, and size 30.
Transpiled circuit index 3 (all-vib-c2h) in 0.01 seconds with method rustiq, depth 13, and size 79.
Transpiled circuit index 4 (graph-gnp_k-2) in 0.02 seconds with method rustiq, depth 31, and size 131.
Transpiled circuit index 5 (all-vib-fccf) in 0.04 seconds with method rustiq, depth 50, and size 306.
Transpiled circuit index 6 (all-vib-hno) in 14.03 seconds with method rustiq, depth 22, and size 276.
Transpiled circuit index 7 (all-vib-bhf2) in 3.15 seconds with method rustiq, depth 13, and size 155.
Transpiled circuit index 8 (LiH) in 0.03 seconds with method rustiq, depth 54, and size 270.
Transpiled circuit index 9 (uf20-ham) in 0.04 seconds with method rustiq, depth 65, and size 398.
Transpiled circuit index 10 (all-vib-fccf) in 0.16 seconds with method rustiq, depth 41, and size 516.
Transpiled circuit index 11 (all-vib-fccf) in 0.02 seconds with method rustiq, depth 34, and size 189.
Transpiled circuit index 12 (all-vib-ch2) in 0.03 seconds with method rustiq, depth 49, and size 240.
Transpiled circuit index 13 (tfim) in 0.05 seconds with method rustiq, depth 20, and size 366.
Transpiled circuit index 14 (all-vib-cyclo_propene) in 9.08 seconds with method rustiq, depth 16, and size 277.
Transpiled circuit index 15 (graph-gnp_k-4) in 0.04 seconds with method rustiq, depth 116, and size 612.
Transpiled circuit index 16 (all-vib-hc3h2cn) in 13.89 seconds with method rustiq, depth 2, and size 257.
Transpiled circuit index 17 (TSP_Ncity-4) in 0.05 seconds with method rustiq, depth 133, and size 737.
Transpiled circuit index 18 (tfim) in 0.11 seconds with method rustiq, depth 25, and size 680.
Transpiled circuit index 19 (all-vib-h2co) in 27.19 seconds with method rustiq, depth 66, and size 983.
Transpiled circuit index 20 (Be2) in 0.07 seconds with method rustiq, depth 215, and size 1030.
Transpiled circuit index 21 (graph-complete_bipart) in 0.14 seconds with method rustiq, depth 328, and size 1918.
Transpiled circuit index 22 (all-vib-f2) in 0.05 seconds with method rustiq, depth 114, and size 692.
Transpiled circuit index 23 (all-vib-cyclo_propene) in 62.25 seconds with method rustiq, depth 74, and size 2348.
Transpiled circuit index 24 (TSP_Ncity-5) in 0.20 seconds with method rustiq, depth 436, and size 3605.
Transpiled circuit index 25 (H2) in 0.21 seconds with method rustiq, depth 643, and size 3476.
Transpiled circuit index 26 (uuf100-ham) in 0.24 seconds with method rustiq, depth 678, and size 6120.
Transpiled circuit index 27 (ham-graph-gnp_k-5) in 0.22 seconds with method rustiq, depth 588, and size 5241.
Transpiled circuit index 28 (tfim) in 0.34 seconds with method rustiq, depth 340, and size 5901.
Transpiled circuit index 29 (uuf100-ham) in 0.33 seconds with method rustiq, depth 881, and size 7667.
Transpiled circuit index 30 (flat100-ham) in 0.31 seconds with method rustiq, depth 279, and size 4910.
Transpiled circuit index 31 (uf100-ham) in 0.38 seconds with method rustiq, depth 1138, and size 10607.
Transpiled circuit index 32 (OH) in 0.38 seconds with method rustiq, depth 1148, and size 6512.
Transpiled circuit index 33 (HF) in 0.37 seconds with method rustiq, depth 1090, and size 6256.
Transpiled circuit index 34 (BH) in 0.37 seconds with method rustiq, depth 1148, and size 6501.
Tabela de resultados (pulando visualização pois os circuitos de saída são muito grandes):
summary_ham = (
results_ham.groupby("method")[["depth", "size", "runtime"]]
.mean()
.round(2)
)
print(summary_ham)
results_ham
depth size runtime
method
ai 316.86 2181.26 5.97
rustiq 281.94 2268.80 3.86
sabre 337.97 2120.14 3.07
method qc_name qc_index num_qubits \
0 sabre all-vib-o3 0 4
1 sabre all-vib-c2h 1 4
2 sabre all-vib-bh 2 2
3 sabre all-vib-c2h 3 3
4 sabre graph-gnp_k-2 4 4
.. ... ... ... ...
100 rustiq flat100-ham 30 90
101 rustiq uf100-ham 31 46
102 rustiq OH 32 10
103 rustiq HF 33 10
104 rustiq BH 34 10
ops depth size runtime
0 {'rz': 28, 'sx': 24, 'cz': 6} 6 58 0.016597
1 {'rz': 17, 'sx': 16, 'cz': 4, 'x': 2} 2 39 1.102089
2 {'sx': 14, 'rz': 13, 'cz': 3} 3 30 0.011042
3 {'sx': 46, 'rz': 45, 'cz': 18, 'x': 6} 18 115 0.025816
4 {'sx': 49, 'rz': 47, 'cz': 24, 'x': 9} 24 129 0.023077
.. ... ... ... ...
100 {'sx': 2709, 'cz': 1379, 'rz': 817, 'x': 5} 279 4910 0.309448
101 {'sx': 6180, 'cz': 3120, 'rz': 1303, 'x': 4} 1138 10607 0.380977
102 {'sx': 3330, 'cz': 1704, 'rz': 1455, 'x': 23} 1148 6512 0.383564
103 {'sx': 3213, 'cz': 1620, 'rz': 1406, 'x': 17} 1090 6256 0.368578
104 {'sx': 3331, 'cz': 1704, 'rz': 1447, 'x': 19} 1148 6501 0.374822
[105 rows x 8 columns]
Visualizar desempenho baseado no índice do circuito:
plot_transpilation_metrics(
results_ham, "Transpilation Metrics for Hamiltonian Circuits"
)

Visualizar a porcentagem de circuitos para os quais cada método teve melhor desempenho.
def analyze_and_plot_best_methods(results, metric):
"""
Analyze the best-performing methods for a given metric and plot a pie chart.
Parameters:
results (DataFrame): The input DataFrame containing method performance data.
metric (str): The metric to evaluate ("depth" or "size").
"""
method_counts = Counter()
for qc_idx, group in results.groupby("qc_index"):
min_value = group[metric].min()
# Find all methods that achieved this minimum value
best_methods = group[group[metric] == min_value]["method"]
# Update counts for all best methods (handling ties)
method_counts.update(best_methods)
best_method_counts = dict(
sorted(method_counts.items(), key=lambda x: x[1], reverse=True)
)
# Print summary
print(f"Best-performing methods based on {metric}:")
for method, count in best_method_counts.items():
print(f" {method}: {count} circuit(s)")
# Plot pie chart
num_methods = len(best_method_counts)
colors = plt.cm.viridis_r(range(0, 256, 256 // num_methods))
plt.figure(figsize=(5, 5))
plt.pie(
best_method_counts.values(),
labels=best_method_counts.keys(),
autopct="%1.1f%%",
startangle=140,
wedgeprops={"edgecolor": "black"},
textprops={"fontsize": 10},
colors=colors,
)
plt.title(
f"Percentage of Circuits Method Performed Best for {metric.capitalize()}",
fontsize=12,
fontweight="bold",
)
plt.show()
analyze_and_plot_best_methods(results_ham, "depth")
analyze_and_plot_best_methods(results_ham, "size")
Best-performing methods based on depth:
ai: 16 circuit(s)
rustiq: 16 circuit(s)
sabre: 10 circuit(s)
Best-performing methods based on size:
sabre: 18 circuit(s)
rustiq: 14 circuit(s)
ai: 10 circuit(s)
Análise dos resultados de compilação de circuitos Hamiltonianos
Nesta seção, avaliamos o desempenho de três métodos de transpilação — SABRE, o transpilador com IA e Rustiq — em circuitos quânticos construídos com PauliEvolutionGate, que são comumente usados em tarefas de simulação Hamiltoniana.
O Rustiq teve o melhor desempenho em média em termos de profundidade do circuito**, alcançando aproximadamente 20% menor profundidade do que o SABRE. Isso é esperado, pois o Rustiq é especificamente projetado para sintetizar operações PauliEvolutionGate com estratégias de decomposição otimizadas de baixa profundidade. Além disso, o gráfico de profundidade mostra que à medida que os circuitos aumentam em tamanho e complexidade, o Rustiq escala de forma mais eficaz, mantendo profundidade significativamente menor do que IA e SABRE em circuitos maiores.
O transpilador de IA mostrou desempenho forte e consistente para profundidade do circuito, superando consistentemente o SABRE na maioria dos circuitos. No entanto, incorreu no maior tempo de execução, especialmente em circuitos maiores, o que pode limitar sua praticidade em cargas de trabalho sensíveis ao tempo. Sua escalabilidade em tempo de execução permanece uma limitação chave, mesmo que ofereça melhorias sólidas em profundidade.
O SABRE, embora produza a maior profundidade média, alcançou a menor contagem média de portas, seguido de perto pelo transpilador de IA. Isso está alinhado com o design da heurística do SABRE, que prioriza minimizar a contagem de portas diretamente. O Rustiq, apesar de sua força em reduzir profundidade, teve a maior contagem média de portas, o que é uma compensação notável a considerar em aplicações onde o tamanho do circuito importa mais do que a duração do circuito.
Resumo
Embora o transpilador de IA geralmente forneça resultados melhores do que o SABRE, particularmente em profundidade do circuito, a conclusão não deve ser simplesmente "sempre use o transpilador de IA". Há nuances importantes a considerar:
-
O transpilador de IA é tipicamente confiável e fornece circuitos otimizados em profundidade, mas vem com compensações em tempo de execução, e também tem outras limitações, incluindo mapas de acoplamento suportados e capacidades de síntese. Estes estão detalhados na documentação do Qiskit Transpiler Service.
-
Em alguns casos, particularmente com circuitos muito grandes ou específicos de hardware, o transpilador de IA pode não ser tão eficaz. Nesses casos, o transpilador SABRE padrão permanece extremamente confiável e pode ser otimizado ainda mais ajustando seus parâmetros (veja o tutorial de otimização SABRE).
-
Também é importante considerar a estrutura do circuito ao escolher um método. Por exemplo,
rustiqé projetado especificamente para circuitos envolvendoPauliEvolutionGatee frequentemente produz o melhor desempenho para problemas de simulação Hamiltoniana.
Recomendação:
Não existe uma estratégia de transpilação única para todos os casos. Os usuários são encorajados a compreender a estrutura de seu circuito e testar múltiplos métodos de transpilação — incluindo IA, SABRE e ferramentas especializadas como Rustiq — para encontrar a solução mais eficiente para seu problema específico e restrições de hardware.
Passo 3: Executar usando primitivas Qiskit
Como este tutorial foca em transpilação, nenhum experimento é executado em um dispositivo quântico. O objetivo é aproveitar as otimizações do Passo 2 para obter um circuito transpilado com profundidade e contagem de portas reduzidas.
Passo 4: Pós-processar e retornar resultado no formato clássico desejado
Como não há execução para este notebook, não há resultados para pós-processar.
Referências
[1] "LightSABRE: A Lightweight and Enhanced SABRE Algorithm". H. Zou, M. Treinish, K. Hartman, A. Ivrii, J. Lishman et al. https://arxiv.org/abs/2409.08368
[2] "Practical and efficient quantum circuit synthesis and transpiling with Reinforcement Learning". D. Kremer, V. Villar, H. Paik, I. Duran, I. Faro, J. Cruz-Benito et al. https://arxiv.org/abs/2405.13196
[3] "Pauli Network Circuit Synthesis with Reinforcement Learning". A. Dubal, D. Kremer, S. Martiel, V. Villar, D. Wang, J. Cruz-Benito et al. https://arxiv.org/abs/2503.14448