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.

Qamomile v0.12.1

Qamomile v0.12.1はv0.12.0に続く改善リリースで、フロントエンドの操作性とバグ修正に注力しています。フロントエンドには2つの使い勝手の改善が入りました — 単一qubitゲートがVector[Qubit]に対するブロードキャストに対応したこと(明示的なループを書かずにレジスタ全体への層を1行で書けるようになりました)、およびサブ@qkernelの呼び出し側がPythonのリテラル(int / float / bool)をUInt / Float / Bitパラメータに対してそのまま渡せるようになったことです。QURI Partsでgamma * Jijのようなパラメータの線形結合が扱えるようになり、QAOAの典型パターンで長らく発生していたtranspileエラーが解消されました。コンパイラ関連のバグ2件(QAOAをブロックしていたネストループの名前衝突、および上記のQURI Parts側の問題)が修正され、qaoa_graph_partitionチュートリアルはOMMXのSampleSet APIを使う構成へ書き換えられました。

pip install qamomile==0.12.1

新機能

単一qubitゲートをqubit配列にブロードキャスト

単一qubitゲート(hxyzstsdgtdgrxryrzp)がVector[Qubit]を直接受け取り、レジスタの各要素にゲートを適用するようになりました。ブロードキャスト形式は、手書きのfor i in qmc.range(n): q[i] = qmc.h(q[i])(他の単一qubitゲートも同様)が出力するのと同じForOperation IRに落ちるため、リソース推定・トランスパイル・可視化のいずれも見えるIRは同じです — ソースが短くなるだけです。回転ゲートの場合、同じスカラー角度がすべてのqubitに共有されます。qubitごとに角度を変える層は引き続きVector[Float]へ明示的にindexアクセスするループが必要です(#360)。

import qamomile.circuit as qmc
from qamomile.qiskit import QiskitTranspiler


@qmc.qkernel
def rotation_layer_broadcast(n: qmc.UInt, theta: qmc.Float) -> qmc.Vector[qmc.Bit]:
    q = qmc.qubit_array(n, name="q")
    q = qmc.h(q)            # レジスタ全体にHadamardをブロードキャスト
    q = qmc.ry(q, theta)    # 共有スカラー角度をレジスタ全体にブロードキャスト
    return qmc.measure(q)


transpiler = QiskitTranspiler()
exe = transpiler.transpile(
    rotation_layer_broadcast,
    bindings={"n": 4},
    parameters=["theta"],
)

ブロードキャストと明示的なループを並べて比較する解説は、更新されたチュートリアル02 — パラメータ付き量子カーネルを参照してください。

サブqkernel呼び出しでのスカラーリテラル自動昇格

サブ@qkernelがスカラー型qmc.UInt / qmc.Float / qmc.Bitのパラメータを宣言している場合、呼び出し側はPythonリテラルをそのまま渡せるようになりました — intUIntへ、int / floatFloatへ、boolBitへ昇格されます。helper(q, 0, 0.5)helper(q, qmc.uint(0), qmc.float_(0.5))と等価です。これはfloat | Floatを受け付けてきたqmc.rxなど、既存の組み込みゲートプリミティブのリテラル受け入れパターンと揃えたものです。副次的な効果として、def f(n: qmc.UInt = 4)のようなスカラーデフォルト値もHandleコンストラクタで明示的にラップしなくても動くようになりました(#372)。

昇格は保守的に行われます。トリガーされるのは、宣言された型が3つのスカラーHandleクラスのいずれかちょうどであり、リテラルが対応するプリミティブである場合に限られます。boolint → UIntおよびint → Floatの経路から意図的に除外しているため、Trueが暗黙のうちにUInt(1)になることはありません。すでにHandleである引数や配列型のパラメータは変更されずに通過するため、既存の記号的実行のパスには影響しません。

import qamomile.circuit as qmc
from qamomile.qiskit import QiskitTranspiler


@qmc.qkernel
def rotate_first(
    q: qmc.Vector[qmc.Qubit],
    idx: qmc.UInt,
    angle: qmc.Float,
) -> qmc.Vector[qmc.Qubit]:
    q[idx] = qmc.ry(q[idx], angle)
    return q


@qmc.qkernel
def helper_with_literals(n: qmc.UInt) -> qmc.Vector[qmc.Bit]:
    q = qmc.qubit_array(n, name="q")
    q = rotate_first(q, 0, 0.5)   # int / floatリテラルがそのまま受け付けられる
    return qmc.measure(q)


transpiler = QiskitTranspiler()
exe = transpiler.transpile(helper_with_literals, bindings={"n": 3})

リテラル昇格の便利さを明示的に取り扱うように更新されたチュートリアル06 — 再利用パターンも参照してください。

バグ修正

ドキュメント

さらに詳しく