Skip to main content
IBM Quantum Platform

Iniciação rápida

Este guia apresenta um exemplo mínimo funcional do qiskit-addon-obp pacote. Utilizamos a retropropagação de operadores (OBP) para reduzir a profundidade de um circuito quântico, incorporando as portas finais ao observável.

Um valor esperado ⟨O⟩=⟨ψ∣U†OU∣ψ⟩\langle O \rangle = \langle \psi | U^\dagger O U | \psi \rangle permanece inalterado se retirarmos um bloco de portas no final do circuito UU e conjugarmos a observável por ele, classicamente. O OBP aplica esse procedimento repetidamente, avaliando parte do circuito de forma clássica, de modo que apenas um circuito mais simples seja executado no hardware. O preço a pagar é que cada porta absorvida pode expandir o observável em mais termos de Pauli; portanto, a profundidade economizada deve ser ponderada em relação ao aumento do observável.

Para ver exemplos de como criar fluxos de trabalho realistas com essa ferramenta e executá-los em hardware quântico, confira os tutoriais na Plataforma de Computação Quântica Aberta ( IBM Quantum Platform, OBP Tutorial ).


Preparar os dados para o OBP

O OBP recebe como entrada uma lista de fatias de circuito e um observável. Ele retropropaga as fatias, uma de cada vez, a partir do final do circuito até o observável, reduzindo a profundidade do circuito à custa de termos de Pauli adicionais no observável. Aqui, geramos um circuito de evolução temporal para um modelo de Heisenberg de 10 qubits e o dividimos por tipo de porta.

A seguir, desenhamos o circuito original e, em seguida, o mesmo circuito reorganizado com barreiras que marcam os limites das fatias — cada fatia é uma unidade que pode ser incorporada ao observável em uma única etapa de retropropagação.

import numpy as np
from qiskit.quantum_info import SparsePauliOp
from qiskit.synthesis import LieTrotter
from qiskit.transpiler import CouplingMap
from qiskit_addon_utils.problem_generators import (
    generate_time_evolution_circuit,
    generate_xyz_hamiltonian,
)
from qiskit_addon_utils.slicing import combine_slices, slice_by_gate_types

# Generate a circuit to reduce
coupling_map = CouplingMap.from_heavy_hex(3, bidirectional=False)
reduced_coupling_map = coupling_map.reduce(
    [0, 13, 1, 14, 10, 16, 5, 12, 8, 18]
)

hamiltonian = generate_xyz_hamiltonian(
    reduced_coupling_map,
    coupling_constants=(np.pi / 8, np.pi / 4, np.pi / 2),
    ext_magnetic_field=(np.pi / 3, np.pi / 6, np.pi / 9),
)

circuit = generate_time_evolution_circuit(
    hamiltonian,
    time=0.2,
    synthesis=LieTrotter(reps=2),
)

# Slice the circuit and define an observable
slices = slice_by_gate_types(circuit)
observable = SparsePauliOp("IIIIIIIIIZ")

print(f"Original circuit depth: {circuit.depth()}")
print(f"Number of slices: {len(slices)}")
print(f"Observable terms: {len(observable)}")

Output:

Original circuit depth: 18
Number of slices: 18
Observable terms: 1
# Recombine the slices with barriers to make the slice boundaries visible
sliced_circuit = combine_slices(slices, include_barriers=True)

print("Original circuit:")
display(circuit.draw("mpl", scale=0.6, fold=-1))
print("Sliced circuit (recombined with barriers for visualization)")
sliced_circuit.draw("mpl", scale=0.6, fold=-1)

Output:

Original circuit:
Output of the previous code cell
Sliced circuit (recombined with barriers for visualization)
Output of the previous code cell

Reduza a profundidade do circuito com o OBP

Chamamos essa função backpropagate para incorporar fatias ao observável. A função retorna o observável expandido, as fatias do circuito pelas quais a propagação não ocorreu e os metadados sobre o procedimento.

Se não for controlada, a observável pode crescer na direção de termos d 2n2^n -Pauli. Isso operator_budget limita esse crescimento — aqui, permitimos, no máximo, 8 grupos comutativos em termos de qubits, o que define, aproximadamente, o número de tentativas necessárias para avaliar o observável na QPU. A retropropagação é interrompida assim que a absorção da próxima fatia exceder o orçamento, que é exatamente o que ocorre a seguir: apenas 7 das 18 fatias são absorvidas antes que o observável preencha todos os 8 grupos comutativos e o procedimento seja interrompido.

Para aprofundar a análise do circuito, o argumento de truncation_error_budget palavra-chave da função pode backpropagate ser usado para eliminar termos de Pauli com coeficientes pequenos do observável à medida que este cresce. Isso atenua o crescimento da grandeza observável em troca de um erro proporcional à magnitude dos termos de Pauli que estão sendo truncados. Os dois orçamentos são complementares e podem ser utilizados em conjunto: operator_budget controla a magnitude da variável observável, enquanto truncation_error_budget controla o erro resultante da omissão de termos.

from qiskit_addon_obp import backpropagate
from qiskit_addon_obp.utils.simplify import OperatorBudget

max_qwc_groups = 8
bp_obs, remaining_slices, metadata = backpropagate(
    observable,
    slices,
    operator_budget=OperatorBudget(max_qwc_groups=max_qwc_groups),
)

reduced_circuit = combine_slices(remaining_slices)
num_groups = len(bp_obs.group_commuting(qubit_wise=True))

print(
    f"Backpropagated {metadata.num_backpropagated_slices} of {len(slices)} slices."
)
print(
    f"Reduced circuit depth: {reduced_circuit.depth()} (was {circuit.depth()})"
)
print(f"Observable grew from {len(observable)} to {len(bp_obs)} Pauli terms.")
print(
    f"Filled {num_groups} of {max_qwc_groups} commuting groups, exhausting the budget."
)

Output:

Backpropagated 7 of 18 slices.
Reduced circuit depth: 11 (was 18)
Observable grew from 1 to 18 Pauli terms.
Filled 8 of 8 commuting groups, exhausting the budget.
reduced_circuit.draw("mpl", scale=0.6, fold=-1)

Output:

Output of the previous code cell
Esta página foi útil?
Relate um bug, erro de digitação ou solicite conteúdo no GitHub.