Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

実行モデル:sample()とrun()

Qamomileは量子カーネルの戻り値に応じて2つの実行メソッドを提供します:

量子カーネルの戻り値使用メソッド返される結果
Bit, Vector[Bit], tuple[Bit, ...]sample()SampleResult — カウント付き測定結果
Float (expvalから)run()float — 期待値

この章では両方のメソッドを説明し、期待値計算のためのオブザーバブルを紹介します。

# 最新のQamomileをpipからインストールします!
# !pip install qamomile
import qamomile.circuit as qmc
import qamomile.observable as qmo
from qamomile.qiskit import QiskitTranspiler

transpiler = QiskitTranspiler()

複数量子ビットのsample()

チュートリアル01では単一のBitをサンプリングしました。量子カーネルが複数ビットを返す場合、各測定結果は整数値(0または1)のタプルになります。

@qmc.qkernel
def parity_probe(theta: qmc.Float) -> tuple[qmc.Bit, qmc.Bit]:
    q0 = qmc.qubit(name="q0")
    q1 = qmc.qubit(name="q1")

    q0 = qmc.h(q0)
    q1 = qmc.ry(q1, theta)
    q0, q1 = qmc.cx(q0, q1)

    return qmc.measure(q0), qmc.measure(q1)
parity_probe.draw(theta=0.7)
<Figure size 806x200 with 1 Axes>
exe_sample = transpiler.transpile(parity_probe, parameters=["theta"])
sample_result = exe_sample.sample(
    transpiler.executor(),
    shots=256,
    bindings={"theta": 0.7},
).result()

for outcome, count in sample_result.results:
    print(f"  outcome={outcome}, count={count}")
  outcome=(1, 0), count=11
  outcome=(0, 1), count=18
  outcome=(0, 0), count=119
  outcome=(1, 1), count=108

outcome(0, 1)(1, 0)のようなタプルです。最初の要素はq0に、2番目の要素はq1に対応し、return文での順序と一致します。

ビット順序の規約

Qamomileの出力はビッグエンディアン順序を使用します:最も左の位置が戻り値タプルの最初の量子ビットに対応します。

(measure(q0), measure(q1), measure(q2))を返す量子カーネルの場合:

結果タプルq0q1q2
(0, 1, 1)011
(1, 0, 0)100

タプルの位置iが戻り値の量子ビットiに対応します。

注意:Qiskitは内部的にリトルエンディアンを使用しますが、Qamomileが変換を処理します。結果は常に記述した順序で得られます。

期待値が必要な場合

個々の測定結果ではなく、量子オブザーバブルの期待値(平均値)が必要な場面があります。例えば:

  • VQE(変分量子固有値ソルバー):ψHψ\langle \psi \rvert H \lvert \psi \rangleの最小化

  • QAOA:コスト関数の期待値の評価

  • 量子パラメータに対するあらゆる最適化ループ

このためにQamomileはexpval()run()を提供しています。

Observable型

関連する2つの概念があります:

  1. qmc.Observable — 量子カーネルのシグネチャで使用するハンドル型です。qmc.Floatと同様に、量子カーネルの引数や戻り値の型アノテーションで使用します。

  2. qamomile.observableモジュール — バインディングで渡す具体的なオブザーバブル値を構築する場所です。例えば

import qamomile.observable as qmo

H = qmo.Z(0)                        # 量子ビット0のパウリZ
H = qmo.Z(0) * qmo.Z(1)             # ZZ相互作用
H = 0.5 * qmo.X(0) + 0.3 * qmo.Y(1) # 線形結合

expval():オブザーバブルの測定

expval(qubit, hamiltonian)は期待値ψHψ\langle \psi \rvert H \lvert \psi \rangleψ\lvert \psi \ranglequbitを表し、HHhamiltonianに対応)を計算し、qmc.Floatを返します。expvalからFloatを返す量子カーネルはrun()で実行する必要があります。

@qmc.qkernel
def z_expectation(theta: qmc.Float, hamiltonian: qmc.Observable) -> qmc.Float:
    q = qmc.qubit(name="q")
    q = qmc.ry(q, theta)
    return qmc.expval(q, hamiltonian)


H = qmo.Z(0)
z_expectation.draw(theta=0.7, hamiltonian=H)
<Figure size 864x200 with 1 Axes>

run()による実行

期待値を返す量子カーネルにはsample()の代わりにrun()を使います。オブザーバブルはトランスパイル時にバインドし(測定回路に影響するため)、thetaはスイープ可能なパラメータとして残します。

exe_run = transpiler.transpile(
    z_expectation,
    bindings={"hamiltonian": H},  # Observable bound at transpile time
    parameters=["theta"],  # theta remains sweepable
)

run_result = exe_run.run(
    transpiler.executor(),
    bindings={"theta": 0.7},
).result()

print("expectation value:", run_result)
print("python type:", type(run_result))
expectation value: 0.744140625
python type: <class 'float'>

run().result()はプレーンなfloatを返します — 推定されたψZψ\langle \psi \rvert Z \lvert \psi \rangleの値です。θ=0.7\theta = 0.7の場合、RYゲートが量子ビットを

RY(θ)0=cos(θ2)0+sin(θ2)1R_Y(\theta) \lvert 0 \rangle = \cos\left( \frac{\theta}{2} \right) \lvert 0 \rangle + \sin\left( \frac{\theta}{2} \right) \lvert 1 \rangle

のように回転させ、Zの期待値はcos2(θ2)sin2(θ2)=cos(θ)0.765\cos^2\left( \frac{\theta}{2} \right) - \sin^2\left( \frac{\theta}{2} \right) = \cos(\theta) \approx 0.765となります。

sample()run()

量子カーネルの戻り値実行メソッド.result()の返り値
Bitsample()SampleResult (.results: list[tuple[int, int]])
tuple[Bit, Bit]sample()SampleResult (.results: list[tuple[tuple[int, int], int]])
Vector[Bit]sample()SampleResult (.results: list[tuple[tuple[int, ...], int]])
Float (expvalから)run()float

使い分け:量子カーネルがmeasure()で終わる場合はsample()を使用します。expval()で終わる場合はrun()を使用します。

まとめ

  • sample()は測定ビットを返す量子カーネル用 — カウント付きの測定結果分布が得られます。

  • run()expval()Floatを返す量子カーネル用 — 単一の期待値が得られます。

  • qmc.Observableはハンドル型、qamomile.observable.Z(0)等が具体的な値です。オブザーバブルはトランスパイル時にバインドします。

  • ビット順序はビッグエンディアン:戻り値タプルの位置が量子ビットの順序に対応します。

次へ古典フローパターンqmc.rangeによるループ、qmc.itemsによるスパースデータ、条件分岐。