クイック・スタート
このガイドでは、この qiskit-addon-obp パッケージの最小限の動作例を紹介します。 オペレータバックプロパゲーション(OBP)を用いて、末尾のゲートを観測量に吸収させることで、量子回路の深さを削減する。
回路 から末尾のゲートブロックを取り除き、それによって観測量を古典的に共役させたとしても、期待値 は変わらない。 OBPはこの処理を繰り返し適用し、回路の一部を従来の方法で評価することで、ハードウェア上で実行される回路の規模を小さく抑えます。 その代償として、吸収されるゲートごとに観測量が多様なパウリ項へと展開されることになるため、節約された深さと観測量の増加とのバランスを考慮しなければならない。
このツールを使って現実的なワークフローを構築し、量子ハードウェア上で実行する方法の例については、 IBM Quantum Platform ( OBPチュートリアル )のチュートリアルをご覧ください。
OBP用の入力データを準備する
OBPは、回路スライスのリストと観測可能変数を入力として受け取ります。 これは、回路の末端から観測量へとスライスを1つずつ逆伝播させ、観測量に追加のパウリ項が生じるという代償を払うことで、回路の深さを浅くする。 ここでは、10量子ビットのハイゼンベルクモデルに対する時間発展回路を生成し、ゲート種別ごとに分割します。
以下に、元の回路図を示し、続いてスライスの境界を示すバリアを追加して再構成した同じ回路図を示します。各スライスは、1回のバックプロパゲーションステップで観測可能量に吸収できる単位です。
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:
Sliced circuit (recombined with barriers for visualization)
OBP を使用して回路の深さを削減する
スライスを観測可能対象に吸収するために backpropagate 、を呼び出します。 この関数は、展開されたオブザーバブル、伝播されなかった回路スライス、およびこの処理に関するメタデータを返します。
放置すると、観測量は のパウリ項に向かって増大する可能性がある。 この成長には上限 operator_budget があります。ここでは、クビット単位で可換な群を最大8つまで許容しており、これにより、QPU上で観測量を評価するために必要な試行回数が大まかに決まります。 次のスライスを吸収すると予算を超過してしまう時点で、バックプロパゲーションは停止します。以下の例でもまさにその通りで、観測可能量が8つのコミューティンググループすべてを満たす前に、18個のスライスのうち7個しか吸収されず、処理が停止します。
回路をさらに深く掘り下げるには、``へのキーワード truncation_error_budget 引数を使用して、観測量が大きくなるにつれて、係数の小さいパウリ項を観測量から除外することができます backpropagate 。 これにより、観測量の発振が抑制される一方で、切り捨てられるパウリ項の大きさに比例する誤差が生じる。 この2つの予算は相互補完的な関係にあり、併用することも可能です。 operator_budget 観測可能なもののサイズを制御し、 truncation_error_budget 項を破棄することによって発生するエラー を制御します。
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: