注釈
このページは docs/tutorials/user-transpiled-circuits.ipynb から生成されました。
Primitive を使用したユーザー・トランスパイル回路の送信¶
回路から最高のパフォーマンスを得るために、 Qiskit Runtime サービスは、すべての回路を実行する前に Qiskitのトランスパイラーを通します。 これは通常は良いことですが、引数 skip_transpilation=True
を使用している primitive に渡すことによって、これを無効にしたい場合があります。
たとえば、場合によってはトランスパイラーよりもよく知っている場合や、特定のデバイス上の量子ビットの特定のサブセットをターゲットにしたい場合があります。 このチュートリアルでは、自動トランスパイラーを無効にして、さまざまなトランスパイラー設定のパフォーマンスをテストします。 この例では、回路の作成、トランスパイル、および送信の全プロセスについて説明します。
IBM Quantum デバイスのためのトランスパイル回路¶
以下のコードセルでは、トランスパイラーが最適化しようとする小さな回路を作成します。 この例では、状態 111
をマークするオラクルを使用して、グローバーのアルゴリズムを実行する回路を作成します。 次に、後で比較するために、理想的な分布(これを完全な量子コンピューターで実行した場合に測定すると予想されるもの)をシミュレートします。
[1]:
# Create circuit to test transpiler on
from qiskit import QuantumCircuit
from qiskit.circuit.library import GroverOperator, Diagonal
oracle = Diagonal([1] * 7 + [-1])
qc = QuantumCircuit(3)
qc.h([0, 1, 2])
qc = qc.compose(GroverOperator(oracle))
# Use Statevector object to calculate the ideal output
from qiskit.quantum_info import Statevector
ideal_distribution = Statevector.from_instruction(qc).probabilities_dict()
from qiskit.visualization import plot_histogram
plot_histogram(ideal_distribution)
[1]:
次に、トランスパイルするバックエンドを選択する必要があります。 下のセルでは、セッションを開始するために使用するサービス・インスタンスを作成し、トランスパイラーの情報を含むバックエンド・オブジェクトを取得します。 トランスパイル・プロセスはデバイスによって異なるため、ランタイム・サービスに特定のデバイスを名前で要求します。 この例では、IBM Cloudを通じてのみ利用可能な ibm_algiers
を使用します。
[2]:
from qiskit_ibm_runtime import QiskitRuntimeService
service = QiskitRuntimeService()
backend = service.backend("ibm_algiers")
次に、私たちのバックエンドの回路をトランスパイルします。 optimization_level
が 0
( 最低 ) から 3
(最高) に設定される optimization_level
というパフォーマンスを比較します。 最も低い最適化レベルは、デバイス上で動作する回路を取得するために必要な最小限のものであり、回路の量子ビットをデバイスの量子ビットにマップし、 すべての2量子ビット演算を可能にするスワップゲートを追加します。最も高い最適化レベルはよりスマートであり、多くのトリックを使用してゲート・カウント全体を削減します。 マルチ量子ビットゲートのエラー率は高く、時間の経過とともに量子ビットが減衰するため、回路を短くすればするほど良い結果が得られるはずです。
以下のセルでは、 optimization_level
の両方の値に対して qc
をトランスパイルし、CNOTゲートの数を出力して、トランスパイルされた回路をリストに追加します。 トランスパイラーのアルゴリズムの一部はランダム化されているため、再現性のシードを設定します。
[3]:
# Need to add measurements to the circuit
qc.measure_all()
from qiskit import transpile
circuits = []
for optimization_level in [0, 3]:
t_qc = transpile(
qc, backend, optimization_level=optimization_level, seed_transpiler=0
)
print(f"CNOTs (optimization_level={optimization_level}): ", t_qc.count_ops()["cx"])
circuits.append(t_qc)
CNOTs (optimization_level=0): 27
CNOTs (optimization_level=3): 12
CNOTは通常エラー率が高いため、 optimization_level=3
でトランスパイルされた回路ははるかに優れたパフォーマンスを発揮するはずです。
パフォーマンスを改善するもう 1 つの方法は、アイドリング状態の量子ビットに一連のゲートを適用する dynamic decoupling です。 これにより、環境との不要な相互作用が取り消されます。 以下のセルでは、dynamic decouplingを optimization_level=3
によってトランスパイルされた回路に追加し、それをリストに追加します。
[4]:
from qiskit.transpiler import PassManager, InstructionDurations
from qiskit.transpiler.passes import ASAPSchedule, DynamicalDecoupling
from qiskit.circuit.library import XGate
# Get gate durations so the transpiler knows how long each operation takes
durations = InstructionDurations.from_backend(backend)
# This is the sequence we'll apply to idling qubits
dd_sequence = [XGate(), XGate()]
# Run scheduling and dynamic decoupling passes on circuit
pm = PassManager([ASAPSchedule(durations), DynamicalDecoupling(durations, dd_sequence)])
circ_dd = pm.run(circuits[1])
# Add this new circuit to our list
circuits.append(circ_dd)
Qiskit Runtime を使用したユーザー・トランスパイルの回路の実行¶
この時点で、 ibm_algiers
用にトランスパイルされた回路( circuits
という名前)のリストを持っています。以下のセルでは、sampler primitive のインスタンスを作成し、コンテキストマネージャー (with ...:
) を使用してセッションを開始します。これにより、セッションが自動的に開閉されます。 ここで、 skip_transpilation=True
という引数を渡しています。
コンテキスト・マネージャー内では、回路をサンプリングし、結果を result
に保管します。
[5]:
from qiskit_ibm_runtime import Sampler, Session
with Session(service=service, backend=backend):
sampler = Sampler()
job = sampler.run(
circuits=circuits, # sample all three circuits
skip_transpilation=True,
shots=8000,
)
result = job.result()
最後に、デバイスの実行結果を理想的な分布に対してプロットすることができます。ゲート数が少ないため、 optimization_level=3
の結果は理想的な分布に近く、適用したdynamic decouplingにより、 optimization_level=3 + dd
の結果はさらに理想的な分布に近いことがわかります。
[6]:
from qiskit.visualization import plot_histogram
binary_prob = [quasi_dist.binary_probabilities() for quasi_dist in result.quasi_dists]
plot_histogram(
binary_prob + [ideal_distribution],
bar_labels=False,
legend=[
"optimization_level=0",
"optimization_level=3",
"optimization_level=3 + dd",
"ideal distribution",
],
)
[6]:
これは、結果の各セットと理想的な分布の間の Hellinger fidelity を計算することで確認できます(高いほど良い、1は 完璧な忠実度)。
[7]:
from qiskit.quantum_info import hellinger_fidelity
for counts in result.quasi_dists:
print(
f"{hellinger_fidelity(counts.binary_probabilities(), ideal_distribution):.3f}"
)
0.927
0.938
0.951
[8]:
import qiskit_ibm_runtime
qiskit_ibm_runtime.version.get_version_info()
[8]:
'0.4.0'
[9]:
from qiskit.tools.jupyter import *
%qiskit_version_table
%qiskit_copyright
Version Information
Qiskit Software | Version |
---|---|
qiskit-terra | 0.20.0 |
qiskit-aer | 0.9.1 |
qiskit-ignis | 0.7.0 |
qiskit-ibmq-provider | 0.18.3 |
qiskit-aqua | 0.9.5 |
qiskit | 0.34.0 |
qiskit-nature | 0.3.0 |
qiskit-finance | 0.2.1 |
qiskit-optimization | 0.2.3 |
qiskit-machine-learning | 0.2.1 |
System information | |
Python version | 3.9.10 |
Python compiler | Clang 13.0.0 (clang-1300.0.29.3) |
Python build | main, Jan 15 2022 11:48:00 |
OS | Darwin |
CPUs | 8 |
Memory (Gb) | 32.0 |
Wed Apr 13 19:59:49 2022 BST |
This code is a part of Qiskit
© Copyright IBM 2017, 2022.
This code is licensed under the Apache License, Version 2.0. You may
obtain a copy of this license in the LICENSE.txt file in the root directory
of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
Any modifications or derivative works of this code must retain this
copyright notice, and modified files need to carry a notice indicating
that they have been altered from the originals.