Pular para o conteúdo principal

Representando computadores quânticos para o Transpiler

Versões dos pacotes

O código desta página foi desenvolvido usando os seguintes requisitos. Recomendamos usar estas versões ou mais recentes.

qiskit[all]~=2.3.0
qiskit-ibm-runtime~=0.43.1

Para converter um circuito abstrato em um circuito ISA que possa ser executado em um QPU (unidade de processamento quântico) específico, o Transpiler precisa de certas informações sobre o QPU. Essas informações são encontradas em dois lugares: o objeto BackendV2 (ou o legado BackendV1) ao qual você pretende enviar jobs, e o atributo Target do backend.

  • O Target contém todas as restrições relevantes de um dispositivo, como seus gates de base nativos, conectividade de qubits e informações de pulso ou temporização.
  • O Backend possui um Target por padrão, contém informações adicionais -- como o InstructionScheduleMap, e fornece a interface para envio de jobs de circuitos quânticos.

Você também pode fornecer informações explicitamente para o Transpiler usar, por exemplo, se tiver um caso de uso específico, ou se acreditar que essas informações ajudarão o Transpiler a gerar um circuito mais otimizado.

A precisão com que o Transpiler produz o circuito mais adequado para um hardware específico depende de quanta informação o Target ou Backend possui sobre suas restrições.

nota

Como muitos dos algoritmos de transpilação subjacentes são estocásticos, não há garantia de que um circuito melhor será encontrado.

Esta página mostra vários exemplos de como passar informações do QPU para o Transpiler. Esses exemplos usam o target do backend simulado FakeSherbrooke.

Configuração padrão

O uso mais simples do Transpiler é fornecer todas as informações do QPU fornecendo o Backend ou Target. Para entender melhor como o Transpiler funciona, construa um circuito e transpile-o com diferentes informações, conforme a seguir.

Importe as bibliotecas necessárias e instancie o QPU: Para converter um circuito abstrato em um circuito ISA que possa ser executado em um processador específico, o Transpiler precisa de certas informações sobre o processador. Normalmente, essas informações são armazenadas no Backend ou Target fornecido ao Transpiler, e nenhuma informação adicional é necessária. Porém, você também pode fornecer informações explicitamente para o Transpiler usar, por exemplo, se tiver um caso de uso específico, ou se acreditar que essas informações ajudarão o Transpiler a gerar um circuito mais otimizado.

Este tópico mostra vários exemplos de como passar informações para o Transpiler. Esses exemplos usam o target do backend simulado FakeSherbrooke.

# Added by doQumentation — required packages for this notebook
!pip install -q qiskit qiskit-ibm-runtime
from qiskit_ibm_runtime.fake_provider import FakeSherbrooke

backend = FakeSherbrooke()
target = backend.target

O circuito de exemplo usa uma instância de efficient_su2 da biblioteca de circuitos do Qiskit.

from qiskit.circuit.library import efficient_su2

qc = efficient_su2(12, entanglement="circular", reps=1)

qc.draw("mpl")

Saída da célula de código anterior

Este exemplo usa as configurações padrão para transpilar para o target do backend, que fornece todas as informações necessárias para converter o circuito em um que será executado no backend.

from qiskit.transpiler import generate_preset_pass_manager

pass_manager = generate_preset_pass_manager(
optimization_level=1, target=target, seed_transpiler=12345
)
qc_t_target = pass_manager.run(qc)
qc_t_target.draw("mpl", idle_wires=False, fold=-1)

Saída da célula de código anterior

Este exemplo é usado nas seções posteriores deste tópico para ilustrar que o mapa de acoplamento e os gates de base são as informações essenciais a serem passadas para o Transpiler para uma construção de circuito otimizada. O QPU geralmente pode selecionar configurações padrão para outras informações que não são passadas, como temporização e agendamento.

Mapa de acoplamento

O mapa de acoplamento é um grafo que mostra quais qubits estão conectados e, portanto, possuem gates de dois qubits entre eles. Às vezes esse grafo é direcional, o que significa que os gates de dois qubits só podem ir em uma direção. Porém, o Transpiler sempre pode inverter a direção de um gate adicionando gates de qubit único adicionais. Um circuito quântico abstrato sempre pode ser representado neste grafo, mesmo que sua conectividade seja limitada, introduzindo gates SWAP para mover as informações quânticas.

Os qubits dos nossos circuitos abstratos são chamados de qubits virtuais e os do mapa de acoplamento são qubits físicos. O Transpiler fornece um mapeamento entre qubits virtuais e físicos. Um dos primeiros passos na transpilação, o estágio de layout, realiza esse mapeamento.

nota

Embora o estágio de roteamento esteja entrelaçado com o estágio de layout — que seleciona os qubits reais —, por padrão, este tópico os trata como estágios separados por simplicidade. A combinação de roteamento e layout é chamada de mapeamento de qubits. Saiba mais sobre esses estágios no tópico Estágios do Transpiler.

Passe o argumento de palavra-chave coupling_map para ver seu efeito no Transpiler:

coupling_map = target.build_coupling_map()

pass_manager = generate_preset_pass_manager(
optimization_level=0, coupling_map=coupling_map, seed_transpiler=12345
)
qc_t_cm_lv0 = pass_manager.run(qc)
qc_t_cm_lv0.draw("mpl", idle_wires=False, fold=-1)

Saída da célula de código anterior

Conforme mostrado acima, vários gates SWAP foram inseridos (cada um consistindo em três gates CX), o que causará muitos erros nos dispositivos atuais. Para ver quais qubits são selecionados na topologia real de qubits, use plot_circuit_layout das Visualizações do Qiskit:

from qiskit.visualization import plot_circuit_layout

plot_circuit_layout(qc_t_cm_lv0, backend, view="physical")

Saída da célula de código anterior

Isso mostra que nossos qubits virtuais 0-11 foram mapeados trivialmente para a linha de qubits físicos 0-11. Vamos voltar ao padrão (optimization_level=1), que usa VF2Layout se algum roteamento for necessário.

pass_manager = generate_preset_pass_manager(
optimization_level=1, coupling_map=coupling_map, seed_transpiler=12345
)
qc_t_cm_lv1 = pass_manager.run(qc)
qc_t_cm_lv1.draw("mpl", idle_wires=False, fold=-1)

Saída da célula de código anterior

Agora não há gates SWAP inseridos e os qubits físicos selecionados são os mesmos que ao usar a classe target.

from qiskit.visualization import plot_circuit_layout

plot_circuit_layout(qc_t_cm_lv1, backend, view="physical")

Saída da célula de código anterior

Agora o layout está em um anel. Como esse layout respeita a conectividade do circuito, não há gates SWAP, fornecendo um circuito muito melhor para execução.

Gates de base

Todo computador quântico suporta um conjunto de instruções limitado, chamado de seus gates de base. Todo gate no circuito deve ser traduzido para os elementos desse conjunto. Esse conjunto deve consistir em gates de qubit único e de dois qubits que forneçam um conjunto de gates universal, o que significa que qualquer operação quântica pode ser decomposta nesses gates. Isso é feito pelo BasisTranslator, e os gates de base podem ser especificados como um argumento de palavra-chave para o Transpiler para fornecer essa informação.

basis_gates = list(target.operation_names)
print(basis_gates)
['sx', 'switch_case', 'x', 'if_else', 'measure', 'for_loop', 'delay', 'ecr', 'id', 'reset', 'rz']

Os gates de qubit único padrão no ibm_sherbrooke são rz, x e sx, e o gate de dois qubits padrão é ecr (cross-resonance ecoado). Gates CX são construídos a partir de gates ecr, portanto em alguns QPUs o ecr é especificado como o gate de base de dois qubits, enquanto em outros o cx é o padrão. O gate ecr é a parte de entrelaçamento do gate cx. Além dos gates de controle, também há instruções de delay e measurement.

nota

Os QPUs têm gates de base padrão, mas você pode escolher quaisquer gates que quiser, desde que forneça a instrução ou adicione pulse gates (consulte Criar passes do Transpiler.) Os gates de base padrão são aqueles para os quais foram feitas calibrações no QPU, portanto nenhuma instrução/pulse gate adicional precisa ser fornecida. Por exemplo, em alguns QPUs o cx é o gate de dois qubits padrão e o ecr em outros. Consulte a lista de possíveis gates e operações nativos para mais detalhes.

pass_manager = generate_preset_pass_manager(
optimization_level=1,
coupling_map=coupling_map,
basis_gates=basis_gates,
seed_transpiler=12345,
)
qc_t_cm_bg = pass_manager.run(qc)
qc_t_cm_bg.draw("mpl", idle_wires=False, fold=-1)

Saída da célula de código anterior

Observe que os objetos CXGate foram decompostos em gates ecr e gates de base de qubit único.

Taxas de erro do dispositivo

A classe Target pode conter informações sobre as taxas de erro para operações no dispositivo. Por exemplo, o código a seguir recupera as propriedades do gate de cross-resonance ecoada (ECR) entre o qubit 1 e o qubit 0 (observe que o gate ECR é direcional):

target["ecr"][(1, 0)]
InstructionProperties(duration=5.333333333333332e-07, error=0.007494257741828603)

A saída exibe a duração do gate (em segundos) e sua taxa de erro. Para revelar informações de erro ao Transpiler, construa um modelo de target com os basis_gates e o coupling_map acima e preencha-o com valores de erro do backend FakeSherbrooke.

from qiskit.transpiler import Target
from qiskit.circuit.controlflow import IfElseOp, SwitchCaseOp, ForLoopOp

err_targ = Target.from_configuration(
basis_gates=basis_gates,
coupling_map=coupling_map,
num_qubits=target.num_qubits,
custom_name_mapping={
"if_else": IfElseOp,
"switch_case": SwitchCaseOp,
"for_loop": ForLoopOp,
},
)

for i, (op, qargs) in enumerate(target.instructions):
if op.name in basis_gates:
err_targ[op.name][qargs] = target.instruction_properties(i)

Transpile com nosso novo target err_targ como o target:

pass_manager = generate_preset_pass_manager(
optimization_level=1, target=err_targ, seed_transpiler=12345
)
qc_t_cm_bg_et = pass_manager.run(qc)
qc_t_cm_bg_et.draw("mpl", idle_wires=False, fold=-1)

Saída da célula de código anterior

Como o target inclui informações de erro, o pass VF2PostLayout tenta encontrar os qubits ideais a serem usados, resultando no mesmo circuito que foi originalmente encontrado com os mesmos qubits físicos.

Próximos passos