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.4

Qamomile v0.12.4ではゲート/量子カーネルの制御化の公開APIをqmc.controlledからqmc.controlに改名し、機能を強化しました。1つの制御ゲートに複数の制御引数を同時に渡せるようになり、新しいcontrol_indicesキーワードで制御引数のどの量子ビットをactiveな制御にするかを選べます。symbolicな値を制御量子ビット数に指定することもできます。制御ゲートのワークフロー全体を最初から最後までたどる新しいチュートリアルも追加しました。最適化の面では、BinaryModel.from_higher_isingが3次以上の相互作用項を持つIsingモデルからBinaryModelを構築できるようにしました。さらに、サポートが漏れていたFloatハンドルの符号反転(-theta)ができるようになりました。

pip install qamomile==0.12.4

破壊的変更

qmc.controlledqmc.controlになりました

制御ゲートのエントリポイントがqmc.controlledからqmc.controlに改名され、qmc.controlledはimportできなくなりました。シグネチャはqmc.control(gate, num_controls=1)のままなので、移行は各呼び出し箇所での機械的な改名だけです。呼び出しが返すControlledGateのクラス名はそのままです(#413)。

# before (v0.12.3)
cg = qmc.controlled(qmc.x, num_controls=2)

# after (v0.12.4)
cg = qmc.control(qmc.x, num_controls=2)

制御ゲートのインデックス選択はsymbolic mode専用になりました

ControlledGate.__call__target_indicesキーワードを受け付けなくなり、controlled_indicescontrol_indicesに改名されました。従来のconcrete index-spec形(concreteなnum_controlsとともにインデックスのリストを渡して、1つのVectorのtarget / 制御の量子ビットを選ぶ形)は削除されました。量子ビットの部分選択はsymbolic modeのcontrol_indicesで表現するようになったため(新機能を参照)、target_indices= / controlled_indices=を渡していた呼び出し箇所は、symbolicなnum_controlsの呼び出しに移す必要があります(#413)。

新機能

より表現力の高いqmc.controlによる制御ゲート

qmc.control(gate, num_controls=...)は、任意のビルトインゲート(qmc.xqmc.rxqmc.pなど)やユーザ定義の@qmc.qkernelを、その制御版に変換します。ラッパーを書かずにビルトインを制御化すること自体はv0.12.2から可能でしたが、本リリースではAPIをqmc.controlに改名し、機能を拡張しました。

以下はconcrete mode(num_controlsがPythonのint)の例です。

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

# CCYは制御を2つ持つYです。ラッパーカーネルを使わずに定義できます。
ccy = qmc.control(qmc.y, num_controls=2)


@qmc.qkernel
def demo() -> qmc.Vector[qmc.Bit]:
    q = qmc.qubit_array(3, name="q")
    q[0] = qmc.x(q[0])
    q[1] = qmc.x(q[1])
    q[0], q[1], q[2] = ccy(q[0], q[1], q[2])
    return qmc.measure(q)


exe = QiskitTranspiler().transpile(demo)

symbolic mode(num_controlsqmc.UIntハンドルやn - 1のようなUInt式)では、制御数はtranspile時にbindingsから解決されます。本リリースで新たに、symbolic modeはmulti-argの制御prefix(スカラーのQubitVectorViewVector[Qubit]、またはそれらの混在で、量子ビット数の合計がnum_controlsに一致する複数のpositional制御)と、1つの制御引数のどの量子ビットをactiveな制御として配線し、残りをそのまま素通りさせるかを選ぶcontrol_indicesキーワードを受け付けます。

@qmc.qkernel
def subset_demo(n: qmc.UInt, k_ctrls: qmc.UInt) -> qmc.Vector[qmc.Bit]:
    pool = qmc.qubit_array(n, name="pool")
    tgt = qmc.qubit(name="tgt")
    pool[0] = qmc.x(pool[0])
    pool[1] = qmc.x(pool[1])
    pool[3] = qmc.x(pool[3])  # pool[2]は|0>のまま。これがactiveでない量子ビットです
    # 量子ビット0、1、3だけがactiveな制御として配線され、pool[2]はそのまま素通りします。
    cg = qmc.control(qmc.x, num_controls=k_ctrls)
    pool, tgt = cg(pool, tgt, control_indices=[0, 1, 3])
    return qmc.measure(pool)


exe = QiskitTranspiler().transpile(subset_demo, bindings={"n": 4, "k_ctrls": 3})

より詳しくはチュートリアル04 — ゲートと量子カーネルの制御を参照してください。

高次Isingモデル: BinaryModel.from_higher_ising

BinaryModel.from_higher_ising(higher_ising, constant=0.0, simplify=False)は、インデックスのタプルから係数への辞書からSPIN型のBinaryModelを構築します。相互作用の次数に上限はなく、3次(s_i s_j s_k)、4次、それ以上も扱えます。1つの項の中で重複したインデックスはスピンの恒等式s_i**2 = 1で簡約され((0, 0, 2)(2,)に縮約)、インデックスは連続した範囲に振り直されます(#382)。

from qamomile.optimization.binary_model import BinaryModel

# 1次、2次、そして3次(degree-3)の相互作用項です。
higher_ising = {(0,): 1.0, (0, 1): 2.0, (0, 1, 3): 4.0}
model = BinaryModel.from_higher_ising(higher_ising, constant=8.0)
print(model.num_bits, model.coefficients)
3 {(0,): 1.0, (0, 1): 2.0, (0, 1, 2): 4.0}

Floatハンドルの単項マイナス

Floatハンドルが単項マイナスをサポートするようになり、@qmc.qkernelの中で0.0 - thetaの代わりに-thetaと直接書けます。符号反転は-1.0との乗算に落ちるので、thetaがコンパイル時に束縛されている場合は、発行される回路内のリテラルな角度に畳み込まれます(#401)。

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


@qmc.qkernel
def neg_cancel(theta: qmc.Float) -> qmc.Vector[qmc.Bit]:
    q = qmc.qubit_array(1, name="q")
    q = qmc.ry(q, theta)
    q = qmc.ry(q, -theta)  # Floatハンドルへの単項マイナス。2つの回転は打ち消し合います
    return qmc.measure(q)


exe = QiskitTranspiler().transpile(neg_cancel, bindings={"theta": 1.0})

内部的な変更

リリースを締めくくる内部的な変更が2つあります。1つ目は上記の制御ゲートの作業を支えるもので、2つ目は独立した変更です。

制御ゲートのIRの集約

IRはこれまで、インデックス選択付きの制御ゲートのために、ConcreteControlledUSymbolicControlledUに加えて専用のIndexSpecControlledU演算を持っていました。本リリースではIndexSpecControlledUを廃止し、その機能をSymbolicControlledUに統合します。SymbolicControlledUには2つのフィールドが加わりました。num_control_args(multi-arg形で制御prefixを構成する先頭オペランドの個数)と、control_indices(選択された制御の量子ビット。全体を使う場合はNone)です。JSON / msgpackのワイヤフォーマットにも対応する追加フィールドが入りますが、古いペイロードはnum_control_args=1 / control_indices=Noneとしてデコードされるため、SCHEMA_VERSION1のままで、以前にシリアライズしたブロックも引き続き読み込めます。

import qamomile.circuit as qmc
from qamomile.circuit.ir.serialize import dump_msgpack, load_msgpack
from qamomile.qiskit import QiskitTranspiler


@qmc.qkernel
def mcx_pool(n: qmc.UInt) -> qmc.Vector[qmc.Bit]:
    ctrls = qmc.qubit_array(n, name="ctrls")
    tgt = qmc.qubit(name="tgt")
    cg = qmc.control(qmc.x, num_controls=n)  # プール全体をsymbolicに制御
    ctrls, tgt = cg(ctrls, tgt)
    return qmc.measure(ctrls)


affine = QiskitTranspiler().inline(mcx_pool.build(n=3))
restored = load_msgpack(dump_msgpack(affine))

Why: 新機能のmulti-argの制御prefixとcontrol_indices選択には、全体を使う場合と部分選択の場合の両方を、2つ目の演算型を増やさずに表せる単一のIR演算が必要です。SymbolicControlledUに集約することで、emitパス(Qiskit、QURI Parts、CUDA-Q)を3つの制御ゲート演算で分岐させず、1つの制御ゲート処理経路にまとめられます(#413)。

より早く、より広い量子変数の再束縛チェック

量子変数の禁止された再代入(Qubit / Vector[Qubit]を別の値に束縛し直す、パラメータを新規確保で上書きする、連鎖代入、タプルアンパックの不一致など)を、@qmc.qkernelが定義された時点で検出し、ただちにQubitRebindErrorを送出するようになりました。従来のようにbuild() / transpileの段階まで遅延しません。チェッカが対象とするパターンも従来より広がり、メッセージは問題のパターンと修正案を示します。

Why: 上記の項目とは異なり、これは制御ゲートの作業の一部ではありません。再束縛違反は量子カーネルのソースの構造的な誤りなので、定義時点で具体的なパターンと修正案を添えて報告すれば、無関係なtranspile工程を経たあとではなく、作者が対処できるその場で不具合を捕捉できます。これまでチェッカをすり抜けていた再束縛違反を含む量子カーネルは、定義時点で失敗するようになります(#403)。

バグ修正

ドキュメント

さらに詳しく