Skip to main content
IBM Quantum Platform

分数ゲートを用いた量子カーネル

使用時間の見積もり:Heron r2 プロセッサーで30秒以下(注:これはあくまでも見積もりです。 実行時間は異なるかもしれない)。


学習成果

このチュートリアルを学習し終える頃には、以下の点を理解できるようになるはずです:

  • IBM® QPUにおけるフラクショナルゲートとは何か、そしてそれが回路の深さと実行時間をどのように短縮するのか
  • 分数ゲートの使用に伴う制約(特に、RZZ角の範囲)
  • IBM Quantum Compute Service を使用して、分数ゲートを用いた量子カーネルワークフローを構築する方法
  • フラクショナルゲートの有無によるハードウェア実行メトリクス(深さ、所要時間、非局所ゲート数、忠実度)の比較方法
  • 標準的なQiskitパターンのワークフローを維持しつつ、分数RXゲートのみを使用する方法

前提条件

このチュートリアルを進める前に、以下のトピックについて理解しておいていただくことをお勧めします:


背景

IBM 量子プロセッサ上のフラクショナルゲート

分数ゲートとは、パラメータ化された量子ゲートの一種であり、(特定の範囲内であれば)任意の角度の回転を直接実行できるため、 それらを複数の基本ゲートに分解する必要がなくなります。 物理量子ビット間の固有の相互作用を活用することで、特定のユニタリー演算をハードウェア上でより効率的に実装することができます。

IBM Quantum® Heron QPUは、以下の分数ゲートをサポートしています:

  • RZZ(θ)R_{ZZ}(\theta) にとって 0<θ<π/20 < \theta < \pi / 2
  • RX(θ)R_X(\theta) 任意の実数値に対して θ\theta

これらのゲートは、量子回路の深さと時間の両方を大幅に短縮することができる。 ハミルトニアン・シミュレーションや量子カーネル法など、 RZZR_{ZZ}RXR_X を多用するアプリケーションでは特に有利である、 ハミルトニアン・シミュレーション、量子近似最適化アルゴリズム(QAOA)、量子カーネル法などである。 このチュートリアルでは、実例として量子カーネルに焦点を当てる。

制限

フラクショナル・ゲートは現在実験的な機能で、いくつかの制約がある:

フラクショナルゲートは、標準的なアプローチとは異なるワークフローを必要とする。 このチュートリアルでは、実践的なアプリケーションを通して、分数ゲートの扱い方を説明します。

分数ゲートの詳細については、以下を参照のこと。

RZZ角の制約に対するワークフローの手法

フラクショナルゲートを使用するためのワークフローは、一般的に Qiskitのパターンワークフローに従います。 主な違いは、すべてのRZZ角が制約条件 0<θπ/20 < \theta \leq \pi/2 を満たさなければならないという点です。 この条件を満たすためには、以下で説明する2つのアプローチがあります。 ここでは2番目のアプローチをお勧めします。このチュートリアルでは、量子カーネル法に着想を得た例を用いて、その手法を解説します。 量子カーネルがどのような場面で有用である可能性が高いかをより深く理解するためには、 Liu、Arunachalam、およびTemme(2021) の論文を読むことをお勧めします。

また、 IBM Quantum® Learning の「Quantum Machine Learning」コースにある 「Quantumカーネルのトレーニングチュートリアル」や「 Quantumカーネル 」のレッスンも学習することができます。

1. RZZ角の制約を満たすパラメータ値を生成する

すべてのRZZ角度が有効範囲内にあることを確信している場合、標準的なQiskitパターンのワークフローに従うことができます。 この場合、 PUB の一部としてパラメータ値を送信するだけです。 ワークフローは次のように進む。

pm = generate_preset_pass_manager(backend=backend, ...)
t_circuit = pm.run(circuit)
t_observable = observable.apply_layout(t_circuit.layout)
sampler.run([(t_circuit, parameter_values)])
estimator.run([(t_circuit, t_observable, parameter_values)])

有効範囲外の角度を持つRZZゲートを含む PUB :

'The instruction rzz is supported only for angles in the range [0, pi/2], but an angle (20.0) outside of this range has been requested; via parameter value(s) γ[0]=10.0, substituted in parameter expression 2.0*γ[0].'

このエラーを回避するには、以下で説明する2つ目の方法を使用してください。

2. トランスパイル前に回路にパラメータ値を割り当てる

FoldRzzAngleこの qiskit-ibm-runtime パッケージは、と呼ばれる専用のトランスパイラ・パスを提供します。 このパスは、すべてのRZZ角度がRZZ角度の制約を満たすように、量子回路を変換します。 transpileまたは に generate_preset_pass_manager バックエンドを指定すると、Qiskit は自動的に を量子回路に適用 FoldRzzAngle します。 このアプローチでは、トランスパイレーションの前に量子回路にパラメータ値を割り当てる必要があります。 ワークフローは次のように進行します。

pm = generate_preset_pass_manager(backend=backend, ...)
b_circuit = circuit.assign_parameters(parameter_values)
t_circuit = pm.run(b_circuit)
t_observable = observable.apply_layout(t_circuit.layout)
sampler.run([(t_circuit,)])
estimator.run([(t_circuit, t_observable)])

なお、このワークフローでは、量子回路にパラメータ値を割り当て、パラメータが紐付けられた回路をローカルに保存する必要があるため、最初のアプローチよりも計算コストが高くなる点に留意してください。

Caution

既知の問題に注意してください qiskit-ibm-runtimev0.47.0 では、特定のシナリオにおいて、無効な角度を持つRZZゲートがトランスパイル後も回路内に残る可能性があります。

この問題の進捗状況については、 qiskit-ibm-runtime#2441 を参照してください。 この問題が解決されるまでの間、以下の回避策をお試しください。

pm = generate_preset_pass_manager(backend=backend, ...)
pm.post_optimization = PassManager(
    [
        FoldRzzAngle(),
        Optimize1qGatesDecomposition(target=backend.target),
        RemoveIdentityEquivalent(target=backend.target),
    ]
)
... = pm.run(...)

要件

このチュートリアルを始める前に、以下のものがインストールされていることを確認してください:

  • Qiskit SDK v2.0 またはそれ以降、 可視化サポート付き
  • Qiskit Runtime v0.41 またはそれ以降 (pip install qiskit-ibm-runtime)
  • Qiskit Aer v0.17 以降 (pip install qiskit-aer)
  • Qiskit Basis Constructor (pip install qiskit_basis_constructor)

セットアップ

import matplotlib.pyplot as plt
import numpy as np
from qiskit import QuantumCircuit, generate_preset_pass_manager
from qiskit.circuit import ParameterVector
from qiskit.circuit.library import UGate, n_local, unitary_overlap
from qiskit.transpiler import Target, PassManager
from qiskit.transpiler.passes import (
    Optimize1qGatesDecomposition,
    RemoveIdentityEquivalent,
)
from qiskit_aer.primitives import SamplerV2 as AerSampler
from qiskit_basis_constructor import DEFAULT_EQUIVALENCE_LIBRARY
from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2
from qiskit_ibm_runtime.transpiler.passes import FoldRzzAngle

分数ゲートを有効化し、基底ゲートをチェックする

分数ゲートを使用するには、 use_fractional_gates=True オプションを設定することで、分数ゲートをサポートするバックエンドを入手できる。 バックエンドが分数ゲートをサポートしている場合、 rzzrx がその基底ゲートのリストに表示される。

service = QiskitRuntimeService()
backend = service.least_busy(
    operational=True, simulator=False, min_num_qubits=133
)  # backend should be a heron device or later
backend_name = backend.name
backend_c = service.backend(backend_name)  # w/o fractional gates
backend_f = service.backend(
    backend_name, use_fractional_gates=True
)  # w/ fractional gates
print(f"Backend: {backend_name}")
print(f"No fractional gates: {backend_c.basis_gates}")
print(f"With fractional gates: {backend_f.basis_gates}")
if "rzz" not in backend_f.basis_gates:
    print(f"Backend {backend_name} does not support fractional gates")

Output:

Backend: ibm_marrakesh
No fractional gates: ['cz', 'id', 'rz', 'sx', 'x']
With fractional gates: ['cz', 'id', 'rx', 'rz', 'rzz', 'sx', 'x']

小規模シミュレータの例

このセクションでは、量子カーネル回路を実例として用い、シミュレータ上で Qiskitパターンのワークフローの4つのステップを順を追って解説します。

ステップ1:古典的な入力を量子問題に写像する

量子カーネル回路

このセクションでは、RZZゲートを用いた量子カーネル回路を探求し、分数ゲートのワークフローを紹介する。

まず、カーネル行列の各エントリーを計算する量子回路を構築する。 これは、ZZ特徴マップ回路をユニタリーオーバーラップで組み合わせることによって行われる。 カーネル関数は、特徴マップ空間のベクトルを受け取り、その内積をカーネル行列のエントリとして返す: K(x,y)=Φ(x)Φ(y),K(x, y) = \langle \Phi(x) | \Phi(y) \rangle, ここで、 Φ(x)|\Phi(x)\rangle は特徴マップされた量子状態を表す。

RZZゲートを用いて、ZZ特徴マップ回路を手動で構築する。 zz_feature_mapQiskit には組み込みの機能が用意されていますが、Qiskit v2.4.1 の時点では、RZZ ゲートはサポートされていません( イシューを参照 )。

次に、同一の入力に対するカーネル関数を計算する。例えば、 K(x,x)=1K(x, x) = 1。 ノイズの多い量子コンピュータでは、ノイズのためにこの値が1より小さくなることがある。 結果が1に近いほど、実行時のノイズが少ないことを示す。 このチュートリアルでは、この値を忠実度と呼び、次のように定義する。 fidelity=K(x,x).\text{fidelity} = K(x, x).

optimization_level = 2
shots = 2000
reps = 3
rng = np.random.default_rng(seed=123)
def my_zz_feature_map(num_qubits: int, reps: int = 1) -> QuantumCircuit:
    x = ParameterVector("x", num_qubits * reps)
    qc = QuantumCircuit(num_qubits)
    qc.h(range(num_qubits))
    for k in range(reps):
        K = k * num_qubits
        for i in range(num_qubits):
            qc.rz(x[i + K], i)
        pairs = [(i, i + 1) for i in range(num_qubits - 1)]
        for i, j in pairs[0::2] + pairs[1::2]:
            qc.rzz((np.pi - x[i + K]) * (np.pi - x[j + K]), i, j)
    return qc


def quantum_kernel(num_qubits: int, reps: int = 1) -> QuantumCircuit:
    qc = my_zz_feature_map(num_qubits, reps=reps)
    inner_product = unitary_overlap(qc, qc, "x", "y", insert_barrier=True)
    inner_product.measure_all()
    return inner_product


def random_parameters(inner_product: QuantumCircuit) -> np.ndarray:
    return np.tile(rng.random(inner_product.num_parameters // 2), 2)


def fidelity(result) -> float:
    ba = result.data.meas
    return ba.get_int_counts().get(0, 0) / ba.num_shots

量子カーネル回路とそれに対応するパラメータ値を4~40量子ビットのシステムに対して生成し、その忠実度を評価する。

qubits = list(range(4, 12, 2))
circuits = [quantum_kernel(i, reps=reps) for i in qubits]
params = [random_parameters(circ) for circ in circuits]

この4量子ビット回路は以下のように視覚化されている。

circuits[0].draw("mpl", fold=-1)

Output:

Output of the previous code cell

標準的なQiskitパターンのワークフローでは、パラメータ値は通常、 PUB の一部としてSamplerまたはEstimatorプリミティブに渡されます。 しかし、分数ゲートをサポートするバックエンドを使用する場合、これらのパラメータ値はトランスパイル前に量子回路に明示的に割り当てる必要がある。

b_qc = [
    circ.assign_parameters(param) for circ, param in zip(circuits, params)
]
b_qc[0].draw("mpl", fold=-1)

Output:

Output of the previous code cell

ステップ2:量子ハードウェア実行に向けた問題の最適化

次に、標準的なQiskitのパターンに従って、パスマネージャーを使って回路をトランスパイルする。 generate_preset_pass_manager に分数ゲートをサポートするバックエンドを提供することで、 FoldRzzAngle と呼ばれる特殊なパスが自動的に含まれる。 このパスは、RZZの角度制約に準拠するように回路を修正する。 その結果、先の図で負の値を持つRZZゲートが正の値に変換され、Xゲートがいくつか追加される。

backend_f = service.backend(name=backend_name, use_fractional_gates=True)
# pm_f includes `FoldRzzAngle` pass
pm_f = generate_preset_pass_manager(
    optimization_level=optimization_level, backend=backend_f
)
pm_f.post_optimization = PassManager(
    [
        FoldRzzAngle(),
        Optimize1qGatesDecomposition(target=backend_f.target),
        RemoveIdentityEquivalent(target=backend_f.target),
    ]
)
t_qc_f = pm_f.run(b_qc)
print(t_qc_f[0].count_ops())
t_qc_f[0].draw("mpl", fold=-1)

Output:

OrderedDict({'rz': 35, 'rzz': 18, 'x': 13, 'rx': 9, 'measure': 4, 'barrier': 2})
Output of the previous code cell

分数ゲートの影響を評価するために、非局所ゲート(このバックエンドではCZとRZZ)の数を評価する、 を評価し、回路の深さと持続時間と共に、これらのメトリクスを後で標準的なワークフローのものと比較する。

nnl_f = [qc.num_nonlocal_gates() for qc in t_qc_f]
depth_f = [qc.depth() for qc in t_qc_f]
duration_f = [
    qc.estimate_duration(backend_f.target, unit="u") for qc in t_qc_f
]

ステップ3: Qiskit primitivesを使用して実行する

分数ゲートをサポートするバックエンドでトランスパイルド回路を実行する。

sampler_f = AerSampler.from_backend(backend_f)
job = sampler_f.run(t_qc_f, shots=shots)
print(job.job_id())

Output:

085ce928-767e-4200-93bf-3905e5411cfe

ステップ4:後処理を行い、結果を希望の古典形式で返す

カーネル関数の値 K(x,x)K(x, x) は、出力にゼロのビット列 00...00 が含まれる確率を測定することで求めることができる。

result = job.result()
fidelity_f = [fidelity(result=res) for res in result]
print(fidelity_f)

Output:

[0.929, 0.882, 0.8645, 0.817]

フラクショナルゲートなしのワークフローと回路の比較

このセクションでは、分数ゲートをサポートしていないバックエンドを使用した、Qiskitの標準的なパターンワークフローについて紹介します。 トランスパイルされた回路を比較してみると、(前のセクションで説明した)分数ゲートを使用したバージョンの方が、分数ゲートを使用しないバージョンよりもコンパクトであることがわかるでしょう。

# step 1: map classical inputs to quantum problem
# `circuits` and `params` from the previous section are reused here
# step 2: optimize circuits
backend_c = service.backend(backend_name)  # w/o fractional gates
pm_c = generate_preset_pass_manager(
    optimization_level=optimization_level, backend=backend_c
)
t_qc_c = pm_c.run(circuits)
print(t_qc_c[0].count_ops())
t_qc_c[0].draw("mpl", fold=-1)

Output:

OrderedDict({'rz': 130, 'sx': 80, 'cz': 36, 'measure': 4, 'barrier': 2})
Output of the previous code cell
nnl_c = [qc.num_nonlocal_gates() for qc in t_qc_c]
depth_c = [qc.depth() for qc in t_qc_c]
duration_c = [
    qc.estimate_duration(backend_c.target, unit="u") for qc in t_qc_c
]
# step 3: execute
sampler_c = AerSampler.from_backend(backend_c)
job = sampler_c.run(pubs=zip(t_qc_c, params), shots=shots)
print(job.job_id())

Output:

f2cca29d-7263-4976-9e51-13a91b75c3ae
# step 4: post-processing
result = job.result()
fidelity_c = [fidelity(res) for res in result]
print(fidelity_c)

Output:

[0.8625, 0.7605, 0.702, 0.671]

深度、持続時間、および忠実度の比較

このセクションでは、分数ゲートを持つ回路と持たない回路の非局所ゲートの数と忠実度を比較する。 これは、実行効率と品質という点で、分数ゲートを使用することの潜在的な利点を浮き彫りにしている。

plt.plot(qubits, depth_c, "-o", label="no fractional gates")
plt.plot(qubits, depth_f, "-o", label="with fractional gates")
plt.xlabel("number of qubits")
plt.ylabel("depth")
plt.title("Comparison of depths")
plt.grid()
plt.legend()

Output:

<matplotlib.legend.Legend at 0x116af3cb0>
Output of the previous code cell
plt.plot(qubits, duration_c, "-o", label="no fractional gates")
plt.plot(qubits, duration_f, "-o", label="with fractional gates")
plt.xlabel("number of qubits")
plt.ylabel("duration (µs)")
plt.title("Comparison of durations")
plt.grid()
plt.legend()

Output:

<matplotlib.legend.Legend at 0x11ea4f4d0>
Output of the previous code cell
plt.plot(qubits, nnl_c, "-o", label="no fractional gates")
plt.plot(qubits, nnl_f, "-o", label="with fractional gates")
plt.xlabel("number of qubits")
plt.ylabel("number of non-local gates")
plt.title("Comparison of numbers of non-local gates")
plt.grid()
plt.legend()

Output:

<matplotlib.legend.Legend at 0x1247fc440>
Output of the previous code cell
plt.plot(qubits, fidelity_c, "-o", label="no fractional gates")
plt.plot(qubits, fidelity_f, "-o", label="with fractional gates")
plt.xlabel("number of qubits")
plt.ylabel("fidelity")
plt.title("Comparison of fidelities")
plt.grid()
plt.legend()

Output:

<matplotlib.legend.Legend at 0x120b792b0>
Output of the previous code cell

大規模なハードウェアの例

このセクションでは、最大40キュービットの量子ハードウェアを用いて、分数ゲートを用いた場合と用いない場合について、量子カーネルワークフローのベンチマーク評価を行う。

ステップ1~4をまとめて

このワークフローは、小規模な例と同じ構成になっています。 分数のゲートを含む回路と含まない回路をすべてトランスパイルし、メトリクスを収集した上で、それらの回路を実際の量子ハードウェアに送信します。

# -------------------------Step 1-------------------------
qubits = list(range(4, 44, 4))
circuits = [quantum_kernel(i, reps=reps) for i in qubits]
params = [random_parameters(circ) for circ in circuits]
b_qc = [
    circ.assign_parameters(param) for circ, param in zip(circuits, params)
]


def benchmark(b_qc, backend):
    # -------------------------Step 2-------------------------
    pm = generate_preset_pass_manager(optimization_level, backend=backend)
    if "rzz" in backend.target.operation_names:
        # workaround until https://github.com/Qiskit/qiskit-ibm-runtime/issues/2441 is resolved
        pm.post_optimization = PassManager(
            [
                FoldRzzAngle(),
                Optimize1qGatesDecomposition(target=backend.target),
                RemoveIdentityEquivalent(target=backend.target),
            ]
        )
    t_qc = pm.run(b_qc)
    nnl = [qc.num_nonlocal_gates() for qc in t_qc]
    depth = [qc.depth() for qc in t_qc]
    duration = [
        qc.estimate_duration(backend_f.target, unit="u") for qc in t_qc
    ]

    # -------------------------Step 3-------------------------
    sampler = SamplerV2(mode=backend)
    sampler.options.dynamical_decoupling.enable = True
    sampler.options.dynamical_decoupling.sequence_type = "XY4"
    sampler.options.dynamical_decoupling.skip_reset_qubits = True
    sampler.options.environment.job_tags = ["TUT_FG"]
    job = sampler.run(t_qc, shots=shots)
    job_id = job.job_id()
    return nnl, depth, duration, job_id


def postprocessing(job_id: str):
    # -------------------------Step 4-------------------------
    job = service.job(job_id)
    result = job.result()
    fidelities = [fidelity(result=res) for res in result]
    usage = job.usage()
    return fidelities, usage


backend_f = service.backend(backend_name, use_fractional_gates=True)
nnl_f, depth_f, duration_f, job_id_f = benchmark(
    b_qc, backend_f
)  # step 2 & 3
print("job id (w/ fractional gates):", job_id_f)
fidelity_f, usage_f = postprocessing(job_id_f)  # step 4

Output:

job id (w/ fractional gates): d8uasitbh0os73eqnpig
backend_c = service.backend(backend_name, use_fractional_gates=False)
nnl_c, depth_c, duration_c, job_id_c = benchmark(b_qc, backend_c)
print("job id (w/o fractional gates):", job_id_c)
fidelity_c, usage_c = postprocessing(job_id_c)

Output:

job id (w/o fractional gates): d8uav3lposuc738pruug

次に、各指標を比較します。

plt.plot(qubits, depth_c, "-o", label="no fractional gates")
plt.plot(qubits, depth_f, "-o", label="with fractional gates")
plt.xlabel("number of qubits")
plt.ylabel("depth")
plt.title("Comparison of depths")
plt.grid()
plt.legend()

Output:

<matplotlib.legend.Legend at 0x12461e660>
Output of the previous code cell
plt.plot(qubits, duration_c, "-o", label="no fractional gates")
plt.plot(qubits, duration_f, "-o", label="with fractional gates")
plt.xlabel("number of qubits")
plt.ylabel("duration (µs)")
plt.title("Comparison of durations")
plt.grid()
plt.legend()

Output:

<matplotlib.legend.Legend at 0x11f2ac980>
Output of the previous code cell
plt.plot(qubits, nnl_c, "-o", label="no fractional gates")
plt.plot(qubits, nnl_f, "-o", label="with fractional gates")
plt.xlabel("number of qubits")
plt.ylabel("number of non-local gates")
plt.title("Comparison of numbers of non-local gates")
plt.grid()
plt.legend()

Output:

<matplotlib.legend.Legend at 0x125c91be0>
Output of the previous code cell
plt.plot(qubits, fidelity_c, "-o", label="no fractional gates")
plt.plot(qubits, fidelity_f, "-o", label="with fractional gates")
plt.xlabel("number of qubits")
plt.ylabel("fidelity")
plt.title("Comparison of fidelities")
plt.grid()
plt.legend()

Output:

<matplotlib.legend.Legend at 0x11fcf6e40>
Output of the previous code cell

分数ゲートの有無によるQPUの使用時間を比較する。 次のセルの結果は、QPUの使用時間がほとんど同じであることを示している。

print(f"no fractional gates: {usage_c} seconds")
print(f"fractional gates: {usage_f} seconds")

Output:

no fractional gates: 8 seconds
fractional gates: 8 seconds

上級トピック:分数のRXゲートのみを使用する

分数ゲートを使用する際にワークフローを変更する必要があるのは、主にRZZゲート角度の制限に起因する。 ただし、分数RXゲートのみを使用し、分数RZZゲートを除外する場合は、標準的なQiskitパターンのワークフローに従い続けることができます。 このアプローチは、特に多数のRXゲートやUゲートを含む回路において、全体のゲート数を減らし、性能を向上させる可能性があるため、依然として有意義な利点を提供できる。 このセクションでは、RZZゲートを省き、分数RXゲートだけを使用して回路を最適化する方法を示す。

これをサポートするために、Targetオブジェクトの特定のベーシス・ゲートを無効にできるユーティリティ関数を提供しています。 ここでは、RZZゲートを無効にするために使用する。

def remove_instruction_from_target(target: Target, gate_name: str) -> Target:
    new_target = Target(
        description=target.description,
        num_qubits=target.num_qubits,
        dt=target.dt,
        granularity=target.granularity,
        min_length=target.min_length,
        pulse_alignment=target.pulse_alignment,
        acquire_alignment=target.acquire_alignment,
        qubit_properties=target.qubit_properties,
        concurrent_measurements=target.concurrent_measurements,
    )

    for name, qarg_map in target.items():
        if name == gate_name:
            continue
        instruction = target.operation_from_name(name)
        if qarg_map == {None: None}:
            qarg_map = None
        new_target.add_instruction(instruction, qarg_map, name=name)
    return new_target

U、CZ、RZZゲートで構成される回路を例に挙げる。

qc = n_local(3, "u", "cz", "linear", reps=1)
qc.rzz(1.1, 0, 1)
qc.draw("mpl")

Output:

Output of the previous code cell

まず、分数ゲートをサポートしないバックエンド用に回路をトランスパイルする。

pm_c = generate_preset_pass_manager(
    optimization_level=optimization_level, backend=backend_c
)
t_qc = pm_c.run(qc)
print(t_qc.count_ops())
t_qc.draw("mpl")

Output:

OrderedDict({'rz': 23, 'sx': 16, 'cz': 4})
Output of the previous code cell

次に、RZZゲートを除き、分数RXゲートを用いて同じ回路をトランスパイルする。 この結果、RXゲートの効率的な実装により、総ゲート数はわずかに減少した。

backend_f = service.backend(backend_name, use_fractional_gates=True)
target = remove_instruction_from_target(backend_f.target, "rzz")
pm_f = generate_preset_pass_manager(
    optimization_level=optimization_level,
    target=target,
)
t_qc = pm_f.run(qc)
print(t_qc.count_ops())
t_qc.draw("mpl")

Output:

OrderedDict({'rz': 22, 'sx': 14, 'cz': 4, 'rx': 1})
Output of the previous code cell

分数の受信ゲートを用いてUゲートを最適化する

本節では、前節で紹介した回路をベースに、分数RXゲートを用いてUゲートを最適化する方法を示す。

RZZゲートを除き、分数RXゲートのみを使用した回路をトランスパイルする。 以下に示すように、カスタム分解ルールを導入することで、Uゲートの実装に必要な単一量子ビット・ゲートの数を減らすことができる、 Uゲートの実装に必要な1量子ビットゲートの数を減らすことができる。

この機能については、現在、 GitHub のこのイシューで議論されています。

# special decomposition rule for UGate
x = ParameterVector("x", 3)
zxz = QuantumCircuit(1)
zxz.rz(x[2] - np.pi / 2, 0)
zxz.rx(x[0], 0)
zxz.rz(x[1] + np.pi / 2, 0)
DEFAULT_EQUIVALENCE_LIBRARY.add_equivalence(UGate(x[0], x[1], x[2]), zxz)

次に、この qiskit-basis-constructor パッケージが提供する変換機能を用いて constructor-beta 、トランスパイラーを適用します。 その結果、前回のトランスパイレーションと比較して、ゲート総数が減少した。

pm_f = generate_preset_pass_manager(
    optimization_level=optimization_level,
    target=target,
    translation_method="constructor-beta",
)
t_qc = pm_f.run(qc)
print(t_qc.count_ops())
t_qc.draw("mpl")

Output:

OrderedDict({'rz': 16, 'rx': 9, 'cz': 4})
Output of the previous code cell

次のステップ

推奨事項

この作品に興味を持たれた方は、以下の資料もご参考になるかもしれません:

このページは役に立ちましたか?
バグや誤字の報告、またはコンテンツの要求はGitHubで行ってください。