Pular para o conteúdo principal

Introdução ao serviço de transpilador com IA do Qiskit

Uso estimado de QPU: Nenhum (NOTA: Este tutorial não executa jobs porque está focado em transpilação)

Contexto

O serviço de transpilador com IA do Qiskit (QTS) introduz otimizações baseadas em aprendizado de máquina tanto em passes de roteamento quanto de síntese. Esses modos de IA foram projetados para enfrentar as limitações da transpilação tradicional, particularmente para circuitos de grande escala e topologias de hardware complexas.

A partir de julho de 2025, o Transpiler Service foi migrado para a nova plataforma IBM Quantum® e não está mais disponível. Para as atualizações mais recentes sobre o status do Transpiler Service, consulte a documentação do serviço de transpilador. Você ainda pode usar o transpilador com IA localmente, de forma similar à transpilação padrão do Qiskit. Simplesmente substitua generate_preset_pass_manager() por generate_ai_pass_manager(). Esta função constrói um gerenciador de passes que integra os passes de roteamento e síntese alimentados por IA diretamente no seu fluxo de trabalho de transpilação local.

Características principais dos passes de IA

  • Passes de roteamento: O roteamento alimentado por IA pode ajustar dinamicamente os caminhos dos qubits com base no circuito específico e no backend, reduzindo a necessidade de portas SWAP excessivas.

    • AIRouting: Seleção de layout e roteamento de circuito
  • Passes de síntese: Técnicas de IA otimizam a decomposição de portas multi-qubit, minimizando o número de portas de dois qubits, que são tipicamente mais propensas a erros.

    • AICliffordSynthesis: Síntese de portas Clifford
    • AILinearFunctionSynthesis: Síntese de circuito de função linear
    • AIPermutationSynthesis: Síntese de circuito de permutação
    • AIPauliNetworkSynthesis: Síntese de circuito Pauli Network (disponível apenas no Qiskit Transpiler Service, não no ambiente local)
  • Comparação com transpilação tradicional: O transpilador padrão do Qiskit é uma ferramenta robusta que pode lidar com um amplo espectro de circuitos quânticos de forma eficaz. No entanto, quando os circuitos crescem em escala ou as configurações de hardware se tornam mais complexas, os passes de IA podem oferecer ganhos de otimização adicionais. Ao usar modelos aprendidos para roteamento e síntese, o QTS refina ainda mais os layouts de circuito e reduz a sobrecarga para tarefas quânticas desafiadoras ou de grande escala.

Este tutorial avalia os modos de IA usando tanto passes de roteamento quanto de síntese, comparando os resultados com a transpilação tradicional para destacar onde a IA oferece ganhos de desempenho.

Para mais detalhes sobre os passes de IA disponíveis, consulte a documentação de passes de IA.

Por que usar IA para transpilação de circuitos quânticos?

À medida que os circuitos quânticos crescem em tamanho e complexidade, os métodos de transpilação tradicionais têm dificuldade em otimizar layouts e reduzir contagens de portas de forma eficiente. Circuitos maiores, particularmente aqueles envolvendo centenas de qubits, impõem desafios significativos ao roteamento e síntese devido a restrições de dispositivo, conectividade limitada e taxas de erro de qubits.

É aqui que a transpilação alimentada por IA oferece uma solução potencial. Ao aproveitar técnicas de aprendizado de máquina, o transpilador alimentado por IA no Qiskit pode tomar decisões mais inteligentes sobre roteamento de qubits e síntese de portas, levando a uma melhor otimização de circuitos quânticos de grande escala.

Breves resultados de benchmarking

Graph showing AI transpiler performance against Qiskit

Em testes de benchmarking, o transpilador com IA consistentemente produziu circuitos mais rasos e de maior qualidade em comparação com o transpilador padrão do Qiskit. Para esses testes, usamos a estratégia do gerenciador de passes padrão do Qiskit, configurado com [generate_preset_passmanager]. Embora essa estratégia padrão seja frequentemente eficaz, ela pode ter dificuldades com circuitos maiores ou mais complexos. Em contraste, os passes alimentados por IA alcançaram uma redução média de 24% nas contagens de portas de dois qubits e uma redução de 36% na profundidade do circuito para circuitos grandes (100+ qubits) ao transpilar para a topologia heavy-hex do hardware IBM Quantum. Para mais informações sobre esses benchmarks, consulte este blog.

Este tutorial explora os principais benefícios dos passes de IA e como eles se comparam aos métodos tradicionais.

# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy pandas qiskit qiskit-ibm-runtime qiskit-ibm-transpiler
# This cell is hidden from users;
# it just disables a linting rule.
# ruff: noqa: F811

Requisitos

Antes de iniciar este tutorial, certifique-se de ter o seguinte instalado:

  • Qiskit SDK v1.0 ou posterior, com suporte a visualização
  • Qiskit Runtime (pip install qiskit-ibm-runtime) v0.22 ou posterior
  • Qiskit IBM® Transpiler com modo local de IA (pip install 'qiskit-ibm-transpiler[ai-local-mode]')

Configuração

from qiskit import QuantumCircuit
from qiskit.circuit.library import efficient_su2, PermutationGate
from qiskit.synthesis.qft import synth_qft_full
from qiskit.circuit.random import random_circuit, random_clifford_circuit
from qiskit.transpiler import generate_preset_pass_manager, CouplingMap
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_transpiler import generate_ai_pass_manager
from qiskit.synthesis.permutation import (
synth_permutation_depth_lnn_kms,
synth_permutation_basic,
)
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import time
import logging

seed = 42

# Used for generating permutation circuits in part two for comparison
def generate_permutation_circuit(width, pattern):
circuit = QuantumCircuit(width)
circuit.append(
PermutationGate(pattern=pattern),
qargs=range(width),
)
return circuit

# Creates a Bernstein-Vazirani circuit given the number of qubits
def create_bv_circuit(num_qubits):
qc = QuantumCircuit(num_qubits, num_qubits - 1)
qc.x(num_qubits - 1)
qc.h(qc.qubits)
for i in range(num_qubits - 1):
qc.cx(i, num_qubits - 1)
qc.h(qc.qubits[:-1])
return qc

# Transpile a circuit with a given pass manager and return metrics
def transpile_with_metrics(pass_manager, circuit):
start = time.time()
qc_out = pass_manager.run(circuit)
elapsed = time.time() - start

depth_2q = qc_out.depth(lambda x: x.operation.num_qubits == 2)
gate_count = qc_out.size()

return qc_out, {
"depth_2q": depth_2q,
"gate_count": gate_count,
"time_s": elapsed,
}

# Used for collecting metrics for part 3 of synthesis methods
def synth_transpile_with_metrics(qc, pm, pattern_id, method):
start = time.time()
qc = pm.run(qc)
elapsed = time.time() - start

return {
"Pattern": pattern_id,
"Method": method,
"Depth (2Q)": qc.depth(lambda x: x.operation.num_qubits == 2),
"Gates": qc.size(),
"Time (s)": elapsed,
}

# Ignore logs like "INFO:qiskit_ibm_transpiler.wrappers.ai_local_synthesis:Running Linear Functions AI synthesis on local mode"

logging.getLogger(
"qiskit_ibm_transpiler.wrappers.ai_local_synthesis"
).setLevel(logging.WARNING)

Parte I. Padrões Qiskit

Vamos agora ver como usar o serviço de transpilador com IA com um circuito quântico simples, usando padrões Qiskit. A chave é criar um PassManager com generate_ai_pass_manager() em vez do generate_preset_pass_manager() padrão.

Passo 1: Mapear entradas clássicas para um problema quântico

Nesta seção, testaremos o transpilador com IA no circuito efficient_su2, um ansatz eficiente em hardware amplamente utilizado. Este circuito é particularmente relevante para algoritmos quânticos variacionais (por exemplo, VQE) e tarefas de aprendizado de máquina quântico, tornando-o um caso de teste ideal para avaliar o desempenho da transpilação.

O circuito efficient_su2 consiste em camadas alternadas de rotações de qubit único e portas de emaranhamento como CNOTs. Essas camadas permitem uma exploração flexível do espaço de estados quânticos mantendo a profundidade da porta gerenciável. Ao otimizar este circuito, nosso objetivo é reduzir a contagem de portas, melhorar a fidelidade e minimizar o ruído. Isso o torna um forte candidato para testar a eficiência do transpilador com IA.

# For our transpilation, we will use a large circuit of 101 qubits
qc = efficient_su2(90, entanglement="circular", reps=1).decompose()

# Draw a smaller version of the circuit to get a visual representation
qc_small = efficient_su2(5, entanglement="circular", reps=1).decompose()
qc_small.draw(output="mpl")

Output of the previous code cell

Passo 2: Otimizar o problema para execução em hardware quântico

Escolher um backend

Para este exemplo, selecionamos o backend operacional IBM Quantum menos ocupado que não é um simulador e tem pelo menos 100 qubits:

Nota: Como o backend menos ocupado pode mudar ao longo do tempo, diferentes dispositivos podem ser selecionados para diferentes execuções. Propriedades específicas do dispositivo, como mapas de acoplamento, podem levar a diferenças nos circuitos transpilados.

service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=100
)
cm = backend.coupling_map
print(f"Using backend: {backend.name}")
Using backend: ibm_torino

Criar gerenciadores de passes com IA e tradicionais

Para avaliar a eficácia do transpilador com IA, realizaremos duas execuções de transpilação. Primeiro, transpilaremos o circuito usando o transpilador com IA. Em seguida, executaremos uma comparação transpilando o mesmo circuito sem o transpilador com IA, usando métodos tradicionais. Ambos os processos de transpilação usarão o mesmo mapa de acoplamento do backend escolhido e o nível de otimização definido como 3 para uma comparação justa.

Ambos esses métodos refletem a abordagem padrão para criar instâncias de PassManager para transpilar circuitos no Qiskit.

pm_ai = generate_ai_pass_manager(
optimization_level=3,
ai_optimization_level=3,
coupling_map=cm,
include_ai_synthesis=True, # used for part 3 when comparing synthesis methods
)

pm_no_ai = generate_preset_pass_manager(
optimization_level=3,
coupling_map=cm,
seed_transpiler=seed, # note that the AI pass manager does not currently support seeding
)

Transpile os circuitos e registre os tempos.

# Transpile using standard (non-AI) pass manager
_, metrics_no_ai = transpile_with_metrics(pm_no_ai, qc)
print(
f"Standard transpilation: Depth (2q) {metrics_no_ai['depth_2q']}, "
f"Gate count {metrics_no_ai['gate_count']}, Time {metrics_no_ai['time_s']}"
)

# Transpile using AI pass manager
_, metrics_ai = transpile_with_metrics(pm_ai, qc)
print(
f"AI transpilation : Depth (2q) {metrics_ai['depth_2q']}, "
f"Gate count {metrics_ai['gate_count']}, Time {metrics_ai['time_s']}"
)
Standard transpilation: Depth (2q) 95, Gate count 458, Time 0.04650712013244629
AI transpilation : Depth (2q) 90, Gate count 456, Time 0.9342479705810547

Neste teste, comparamos o desempenho do transpilador com IA e o método de transpilação padrão no circuito efficient_su2. O transpilador com IA alcança uma profundidade de circuito visivelmente mais rasa enquanto mantém uma contagem de portas similar.

  • Profundidade do circuito: O transpilador com IA produz um circuito com profundidade de dois qubits menor. Isso é esperado, pois os passes de IA são treinados para otimizar a profundidade aprendendo padrões de interação de qubits e explorando a conectividade do hardware de forma mais eficaz do que heurísticas baseadas em regras.

  • Contagem de portas: A contagem total de portas permanece similar entre os dois métodos. Isso está alinhado com as expectativas, uma vez que a transpilação padrão baseada em SABRE minimiza explicitamente a contagem de swaps, o que domina a sobrecarga de portas. O transpilador com IA, em vez disso, prioriza a profundidade geral e pode ocasionalmente trocar algumas portas adicionais por um caminho de execução mais curto.

  • Tempo de transpilação: O transpilador com IA leva mais tempo para executar do que o método padrão. Isso se deve ao custo computacional adicional de invocar modelos aprendidos durante o roteamento e a síntese. Em contraste, o transpilador baseado em SABRE agora é significativamente mais rápido após ser reescrito e otimizado em Rust, fornecendo roteamento heurístico altamente eficiente em escala.

É importante notar que esses resultados são baseados em apenas um circuito. Para obter uma compreensão abrangente de como o transpilador com IA se compara aos métodos tradicionais, é necessário testar uma variedade de circuitos. O desempenho do QTS pode variar muito dependendo do tipo de circuito sendo otimizado. Para uma comparação mais ampla, consulte os benchmarks acima ou visite o blog.

Passo 3: Executar usando primitivos Qiskit

Como este tutorial está focado em transpilação, nenhum experimento será executado no dispositivo quântico. O objetivo é aproveitar as otimizações do Passo 2 para obter um circuito transpilado com profundidade ou contagem de portas reduzida.

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.

Parte II. Analisar e fazer benchmark dos circuitos transpilados

Nesta seção, demonstraremos como analisar o circuito transpilado e fazer benchmark dele contra a versão original com mais detalhes. Focaremos em métricas como profundidade do circuito, contagem de portas e tempo de transpilação para avaliar a eficácia da otimização. Além disso, discutiremos como os resultados podem diferir entre vários tipos de circuito, oferecendo insights sobre o desempenho mais amplo do transpilador em diferentes cenários.

# Circuits to benchmark
seed = 42
circuits = [
{
"name": "Random",
"qc": random_circuit(num_qubits=30, depth=10, seed=seed),
},
{
"name": "Clifford",
"qc": random_clifford_circuit(
num_qubits=40, num_gates=200, seed=seed
),
},
{
"name": "QFT",
"qc": synth_qft_full(num_qubits=20, do_swaps=False).decompose(),
},
{
"name": "BV",
"qc": create_bv_circuit(40),
},
]

results = []

# Run the transpilation for each circuit and store the results
for circuit in circuits:
qc_no_ai, metrics_no_ai = transpile_with_metrics(pm_no_ai, circuit["qc"])
qc_ai, metrics_ai = transpile_with_metrics(pm_ai, circuit["qc"])

print("Completed transpilation for", circuit["name"])

results.append(
{
"Circuit": circuit["name"],
"Depth 2Q (No AI)": metrics_no_ai["depth_2q"],
"Gate Count (No AI)": metrics_no_ai["gate_count"],
"Time (No AI)": metrics_no_ai["time_s"],
"Depth 2Q (AI)": metrics_ai["depth_2q"],
"Gate Count (AI)": metrics_ai["gate_count"],
"Time (AI)": metrics_ai["time_s"],
}
)

df = pd.DataFrame(results)
df
Completed transpilation for Random
Completed transpilation for Clifford
Completed transpilation for QFT
Completed transpilation for BV
Circuit  Depth 2Q (No AI)  Gate Count (No AI)  Time (No AI)  \
0 Random 37 221 0.039347
1 Clifford 36 232 0.036633
2 QFT 165 924 0.077458
3 BV 65 155 0.024993

Depth 2Q (AI) Gate Count (AI) Time (AI)
0 24 181 0.773718
1 43 267 1.097431
2 130 913 3.660771
3 70 155 0.345522

Redução percentual média para cada métrica. Positivos são melhorias, negativos são degradações.

# Average reduction from non-AI to AI transpilation as a percentage
avg_reduction_depth = (
(df["Depth 2Q (No AI)"] - df["Depth 2Q (AI)"]).mean()
/ df["Depth 2Q (No AI)"].mean()
* 100
)
avg_reduction_gates = (
(df["Gate Count (No AI)"] - df["Gate Count (AI)"]).mean()
/ df["Gate Count (No AI)"].mean()
* 100
)
avg_reduction_time = (
(df["Time (No AI)"] - df["Time (AI)"]).mean()
/ df["Time (No AI)"].mean()
* 100
)

print(f"Average reduction in depth: {avg_reduction_depth:.2f}%")
print(f"Average reduction in gate count: {avg_reduction_gates:.2f}%")
print(f"Average reduction in transpilation time: {avg_reduction_time:.2f}%")
Average reduction in depth: 11.88%
Average reduction in gate count: 1.04%
Average reduction in transpilation time: -3193.95%
fig, axs = plt.subplots(1, 3, figsize=(21, 6))
df.plot(
x="Circuit",
y=["Depth 2Q (No AI)", "Depth 2Q (AI)"],
kind="bar",
ax=axs[0],
)
axs[0].set_title("Circuit Depth Comparison")
axs[0].set_ylabel("Depth")
axs[0].set_xlabel("Circuit")
axs[0].tick_params(axis="x", rotation=45)
df.plot(
x="Circuit",
y=["Gate Count (No AI)", "Gate Count (AI)"],
kind="bar",
ax=axs[1],
)
axs[1].set_title("Gate Count Comparison")
axs[1].set_ylabel("Gate Count")
axs[1].set_xlabel("Circuit")
axs[1].tick_params(axis="x", rotation=45)
df.plot(x="Circuit", y=["Time (No AI)", "Time (AI)"], kind="bar", ax=axs[2])
axs[2].set_title("Time Comparison")
axs[2].set_ylabel("Time (seconds)")
axs[2].set_xlabel("Circuit")
axs[2].tick_params(axis="x", rotation=45)
fig.suptitle(
"Benchmarking AI transpilation vs Non-AI transpilation for various circuits"
)

plt.tight_layout()
plt.show()

Output of the previous code cell

O desempenho do transpilador com IA varia significativamente com base no tipo de circuito sendo otimizado. Em alguns casos, ele alcança reduções notáveis na profundidade do circuito e contagem de portas em comparação com o transpilador padrão. No entanto, essas melhorias frequentemente vêm com um aumento substancial no tempo de execução.

Para certos tipos de circuitos, o transpilador com IA pode produzir resultados ligeiramente melhores em termos de profundidade do circuito, mas também pode levar a um aumento na contagem de portas e uma penalidade significativa no tempo de execução. Essas observações sugerem que os benefícios do transpilador com IA não são uniformes em todos os tipos de circuito. Em vez disso, sua eficácia depende das características específicas do circuito, tornando-o mais adequado para alguns casos de uso do que para outros.

Quando os usuários devem escolher a transpilação com IA?

O transpilador com IA do Qiskit se destaca em cenários onde os métodos tradicionais de transpilação enfrentam dificuldades, particularmente com circuitos quânticos de grande escala e complexos. Para circuitos envolvendo centenas de qubits ou aqueles direcionados a hardware com mapas de acoplamento complexos, o transpilador com IA oferece otimização superior em termos de profundidade de circuito, contagem de portas e eficiência de tempo de execução. Em testes de benchmarking, ele superou consistentemente os métodos tradicionais, entregando circuitos significativamente mais rasos e reduzindo a contagem de portas, que são críticos para melhorar o desempenho e mitigar o ruído em hardware quântico real.

Os usuários devem considerar a transpilação com IA ao trabalhar com:

  • Circuitos grandes onde os métodos tradicionais falham em lidar eficientemente com a escala.
  • Topologias de hardware complexas onde surgem desafios de conectividade e roteamento de dispositivos.
  • Aplicações sensíveis ao desempenho onde reduzir a profundidade do circuito e melhorar a fidelidade são fundamentais.

Parte III. Explore a síntese de redes de permutação com IA

Redes de permutação são fundamentais na computação quântica, particularmente para sistemas restritos por topologias limitadas. Essas redes facilitam interações de longo alcance trocando dinamicamente qubits para imitar conectividade de todos para todos em hardware com conectividade limitada. Tais transformações são essenciais para implementar algoritmos quânticos complexos em dispositivos de curto prazo, onde as interações frequentemente se estendem além dos vizinhos mais próximos.

Nesta seção, destacamos a síntese de redes de permutação como um caso de uso convincente para o transpilador com IA no Qiskit. Especificamente, o passo AIPermutationSynthesis aproveita a otimização orientada por IA para gerar circuitos eficientes para tarefas de permutação de qubits. Em contraste, abordagens de síntese genéricas frequentemente têm dificuldade em equilibrar contagem de portas e profundidade de circuito, especialmente em cenários com interações densas de qubits ou ao tentar alcançar conectividade completa.

Vamos percorrer um exemplo de padrões Qiskit apresentando a síntese de uma rede de permutação para alcançar conectividade de todos para todos para um conjunto de qubits. Compararemos o desempenho do AIPermutationSynthesis contra os métodos de síntese padrão no Qiskit. Este exemplo demonstrará como o transpilador com IA otimiza para menor profundidade de circuito e contagem de portas, destacando suas vantagens em fluxos de trabalho quânticos práticos. Para ativar o passo de síntese com IA, usaremos a função generate_ai_pass_manager() com o parâmetro include_ai_synthesis definido como True.

Passo 1: Mapear entradas clássicas para um problema quântico

Para representar um problema de permutação clássico em um computador quântico, começamos definindo a estrutura dos circuitos quânticos. Para este exemplo:

  1. Inicialização do circuito quântico: Alocamos 27 qubits para corresponder ao backend que usaremos, que possui 27 qubits.

  2. Aplicar permutações: Geramos dez padrões de permutação aleatórios (pattern_1 até pattern_10) usando uma semente fixa para reprodutibilidade. Cada padrão de permutação é aplicado a um circuito quântico separado (qc_1 até qc_10).

  3. Decomposição de circuito: Cada operação de permutação é decomposta em conjuntos de portas nativos compatíveis com o hardware quântico alvo. Analisamos a profundidade e o número de portas de dois qubits (portas não locais) para cada circuito decomposto.

Os resultados fornecem informações sobre a complexidade de representar problemas de permutação clássicos em um dispositivo quântico, demonstrando os requisitos de recursos para diferentes padrões de permutação.

# Parameters
width = 27
num_circuits = 10

# Set random seed
np.random.seed(seed)

# Generate random patterns and circuits
patterns = [
np.random.permutation(width).tolist() for _ in range(num_circuits)
]
circuits = {
f"qc_{i}": generate_permutation_circuit(width, pattern)
for i, pattern in enumerate(patterns, start=1)
}

# Display one of the circuits
circuits["qc_1"].decompose(reps=3).draw(output="mpl", fold=-1)

Output of the previous code cell

Passo 2: Otimizar problema para execução em hardware quântico

Neste passo, prosseguimos com a otimização usando os passos de síntese com IA.

Para os passos de síntese com IA, o PassManager requer apenas o mapa de acoplamento do backend. No entanto, é importante notar que nem todos os mapas de acoplamento são compatíveis; apenas aqueles nos quais o passo AIPermutationSynthesis foi treinado funcionarão. Atualmente, o passo AIPermutationSynthesis suporta blocos de tamanhos 65, 33 e 27 qubits. Para este exemplo, usamos uma QPU de 27 qubits.

Para comparação, avaliaremos o desempenho da síntese com IA contra métodos genéricos de síntese de permutação no Qiskit, incluindo:

  • synth_permutation_depth_lnn_kms: Este método sintetiza um circuito de permutação para uma arquitetura de vizinho mais próximo linear (LNN) usando o algoritmo de Kutin, Moulton e Smithline (KMS). Ele garante um circuito com profundidade de no máximo nn e tamanho de no máximo n(n1)/2n(n-1)/2, onde tanto a profundidade quanto o tamanho são medidos em termos de portas SWAP.

  • synth_permutation_basic: Esta é uma implementação direta que sintetiza circuitos de permutação sem impor restrições de conectividade ou otimização para arquiteturas específicas. Ela serve como uma linha de base para comparar o desempenho com métodos mais avançados.

Cada um desses métodos representa uma abordagem distinta para sintetizar redes de permutação, fornecendo um benchmark abrangente contra os métodos com IA.

Para mais detalhes sobre métodos de síntese no Qiskit, consulte a documentação da API do Qiskit. Defina o mapa de acoplamento representando a QPU de 27 qubits.

coupling_map = [
[1, 0],
[2, 1],
[3, 2],
[3, 5],
[4, 1],
[6, 7],
[7, 4],
[7, 10],
[8, 5],
[8, 9],
[8, 11],
[11, 14],
[12, 10],
[12, 13],
[12, 15],
[13, 14],
[16, 14],
[17, 18],
[18, 15],
[18, 21],
[19, 16],
[19, 22],
[20, 19],
[21, 23],
[23, 24],
[25, 22],
[25, 24],
[26, 25],
]
CouplingMap(coupling_map).draw()

Output of the previous code cell

Transpile cada um dos circuitos de permutação usando os passos de síntese com IA e métodos de síntese genéricos.

results = []
pm_no_ai_synth = generate_preset_pass_manager(
coupling_map=cm,
optimization_level=1, # set to 1 since we are using the synthesis methods
)

# Transpile and analyze all circuits
for i, (qc_name, qc) in enumerate(circuits.items(), start=1):
pattern = patterns[i - 1] # Get the corresponding pattern

qc_depth_lnn_kms = synth_permutation_depth_lnn_kms(pattern)
qc_basic = synth_permutation_basic(pattern)

# AI synthesis
results.append(
synth_transpile_with_metrics(
qc.decompose(reps=3),
pm_ai,
qc_name,
"AI",
)
)

# Depth-LNN-KMS Method
results.append(
synth_transpile_with_metrics(
qc_depth_lnn_kms.decompose(reps=3),
pm_no_ai_synth,
qc_name,
"Depth-LNN-KMS",
)
)

# Basic Method
results.append(
synth_transpile_with_metrics(
qc_basic.decompose(reps=3),
pm_no_ai_synth,
qc_name,
"Basic",
)
)

results_df = pd.DataFrame(results)

Registre as métricas (profundidade, contagem de portas, tempo) para cada circuito após a transpilação.

# Calculate averages for each metric
average_metrics = results_df.groupby("Method")[
["Depth (2Q)", "Gates", "Time (s)"]
].mean()
average_metrics = average_metrics.round(3) # Round to two decimal places
print("\n=== Average Metrics ===")
print(average_metrics)

# Identify the best non-AI method based on least average depth
non_ai_methods = [
method for method in results_df["Method"].unique() if method != "AI"
]
best_non_ai_method = average_metrics.loc[non_ai_methods][
"Depth (2Q)"
].idxmin()
print(
f"\nBest Non-AI Method (based on least average depth): {best_non_ai_method}"
)

# Compare AI to the best non-AI method
ai_metrics = average_metrics.loc["AI"]
best_non_ai_metrics = average_metrics.loc[best_non_ai_method]

comparison = {
"Metric": ["Depth (2Q)", "Gates", "Time (s)"],
"AI": [
ai_metrics["Depth (2Q)"],
ai_metrics["Gates"],
ai_metrics["Time (s)"],
],
best_non_ai_method: [
best_non_ai_metrics["Depth (2Q)"],
best_non_ai_metrics["Gates"],
best_non_ai_metrics["Time (s)"],
],
"Improvement (AI vs Best Non-AI)": [
ai_metrics["Depth (2Q)"] - best_non_ai_metrics["Depth (2Q)"],
ai_metrics["Gates"] - best_non_ai_metrics["Gates"],
ai_metrics["Time (s)"] - best_non_ai_metrics["Time (s)"],
],
}

comparison_df = pd.DataFrame(comparison)
print("\n=== Comparison of AI vs Best Non-AI Method ===")
comparison_df
=== Average Metrics ===
Depth (2Q) Gates Time (s)
Method
AI 23.9 82.8 0.248
Basic 29.8 91.0 0.012
Depth-LNN-KMS 70.8 531.6 0.017

Best Non-AI Method (based on least average depth): Basic

=== Comparison of AI vs Best Non-AI Method ===
Metric      AI   Basic  Improvement (AI vs Best Non-AI)
0 Depth (2Q) 23.900 29.800 -5.900
1 Gates 82.800 91.000 -8.200
2 Time (s) 0.248 0.012 0.236

Os resultados demonstram que o transpilador com IA supera todos os outros métodos de síntese do Qiskit para este conjunto de circuitos de permutação aleatórios. As principais descobertas incluem:

  1. Profundidade: O transpilador com IA alcança a menor profundidade média, indicando otimização superior dos layouts de circuito.
  2. Contagem de portas: Ele reduz significativamente o número de portas em comparação com outros métodos, melhorando a fidelidade e eficiência de execução.
  3. Tempo de transpilação: Todos os métodos executam muito rapidamente nesta escala, tornando-os práticos para uso. No entanto, o transpilador com IA tem um aumento notável no tempo de execução em comparação com métodos tradicionais devido à complexidade dos modelos de IA usados.

Esses resultados estabelecem o transpilador com IA como a abordagem mais eficaz para este benchmark, particularmente para otimização de profundidade e contagem de portas. Plote os resultados para comparar o desempenho dos passos de síntese com IA contra os métodos de síntese genéricos.

methods = results_df["Method"].unique()

fig, axs = plt.subplots(1, 3, figsize=(18, 5))

# Pivot the DataFrame and reorder columns to ensure AI is first
pivot_depth = results_df.pivot(
index="Pattern", columns="Method", values="Depth (2Q)"
)[["AI", "Depth-LNN-KMS", "Basic"]]
pivot_gates = results_df.pivot(
index="Pattern", columns="Method", values="Gates"
)[["AI", "Depth-LNN-KMS", "Basic"]]
pivot_time = results_df.pivot(
index="Pattern", columns="Method", values="Time (s)"
)[["AI", "Depth-LNN-KMS", "Basic"]]

pivot_depth.plot(kind="bar", ax=axs[0], legend=False)
axs[0].set_title("Circuit Depth Comparison")
axs[0].set_ylabel("Depth")
axs[0].set_xlabel("Pattern")
axs[0].tick_params(axis="x", rotation=45)
pivot_gates.plot(kind="bar", ax=axs[1], legend=False)
axs[1].set_title("2Q Gate Count Comparison")
axs[1].set_ylabel("Number of 2Q Gates")
axs[1].set_xlabel("Pattern")
axs[1].tick_params(axis="x", rotation=45)
pivot_time.plot(
kind="bar", ax=axs[2], legend=True, title="Legend"
) # Show legend on the last plot
axs[2].set_title("Time Comparison")
axs[2].set_ylabel("Time (seconds)")
axs[2].set_xlabel("Pattern")
axs[2].tick_params(axis="x", rotation=45)
fig.suptitle(
"Benchmarking AI Synthesis Methods vs Non-AI Synthesis Methods For Random Permutations Circuits",
fontsize=16,
y=1,
)

plt.tight_layout()
plt.show()

Output of the previous code cell

Este gráfico destaca os resultados individuais para cada circuito (qc_1 até qc_10) em diferentes métodos de síntese:

Embora esses resultados ressaltem a eficácia do transpilador com IA para circuitos de permutação, é importante notar suas limitações. O método de síntese com IA está atualmente disponível apenas para certos mapas de acoplamento, o que pode restringir sua aplicabilidade mais ampla. Essa restrição deve ser considerada ao avaliar seu uso em diferentes cenários.

No geral, o transpilador com IA demonstra melhorias promissoras na otimização de profundidade e contagem de portas para esses circuitos específicos, mantendo tempos de transpilação comparáveis.

Passo 3: Executar usando primitivos Qiskit

Como este tutorial se concentra em transpilação, nenhum experimento será executado no dispositivo quântico. O objetivo é aproveitar as otimizações do Passo 2 para obter um circuito transpilado com profundidade ou contagem de portas reduzida.

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.

Pesquisa do tutorial

Por favor, responda a esta breve pesquisa para fornecer feedback sobre este tutorial. Seus insights nos ajudarão a melhorar nossas ofertas de conteúdo e experiência do usuário.

Link to survey