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.controlledはqmc.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_indicesはcontrol_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.x、qmc.rx、qmc.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_controlsがqmc.UIntハンドルやn - 1のようなUInt式)では、制御数はtranspile時にbindingsから解決されます。本リリースで新たに、symbolic modeはmulti-argの制御prefix(スカラーのQubit、VectorView、Vector[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はこれまで、インデックス選択付きの制御ゲートのために、ConcreteControlledUとSymbolicControlledUに加えて専用のIndexSpecControlledU演算を持っていました。本リリースではIndexSpecControlledUを廃止し、その機能をSymbolicControlledUに統合します。SymbolicControlledUには2つのフィールドが加わりました。num_control_args(multi-arg形で制御prefixを構成する先頭オペランドの個数)と、control_indices(選択された制御の量子ビット。全体を使う場合はNone)です。JSON / msgpackのワイヤフォーマットにも対応する追加フィールドが入りますが、古いペイロードはnum_control_args=1 / control_indices=Noneとしてデコードされるため、SCHEMA_VERSIONは1のままで、以前にシリアライズしたブロックも引き続き読み込めます。
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)。
バグ修正¶
形状依存のstdlibゲートを使うネストした量子カーネルが正しく特殊化されるようになりました(#404、#392を修正)。ある
@qmc.qkernelが、呼び出し側でサイズの定まるVector[Qubit]に対して形状依存のstdlibゲート(qmc.qft、qmc.iqft)を使う別の量子カーネルを呼ぶとき、その呼び出し先は具体的なレジスタサイズに対して再トレースされるようになりました。これまでは形状依存のゲートが何も発行されないことがありました。可視化の改善: 制御化されたビルトインゲート(controlled-SWAPを含む)が、汎用の箱ではなく専用の制御 / targetの記号で描画されます(#409)。controlled-Uの箱には、制御化された対象ゲートの名前とその古典引数が表示されます(#413)。束縛済み
Vectorオペランドを持つ深くネストしたinlineブロックは、ゲートを正しいワイヤに配線します(#410)。またVectorスライスのパターン(リテラルで束縛されたスライス、ネストしたスライス、スライス代入のブロードキャスト)が、正しいルートレジスタのワイヤ上に描画されます(#408、#413)。
ドキュメント¶
新しいチュートリアル04 — ゲートと量子カーネルの制御は、
qmc.controlを最初から最後まで解説します。ビルトインとユーザ量子カーネルの制御化、concrete modeとsymbolic modeの対比、power=、デフォルト引数、multi-argの制御prefix、control_indices選択、そして各誤用が送出するエラーまでを扱います。新しいQURI Partsサポートの統合記事は、量子カーネルをQURI Partsにtranspileして、Qulacsの状態ベクトルシミュレータ上で実行する方法を、MaxCut QAOAの例とともに最初から最後まで示します(#386)。
新しいハイブリッド量子ニューラルネットワーク(HQNN)の記事は、CNNの特徴抽出器と量子変分回路をFashion-MNIST上で同時に学習させ、parameter-shift則で量子層を逆伝播します(#319)。
量子誤り訂正のチュートリアルを書き直しました。量子誤り訂正入門(3量子ビットのビット反転 / 位相反転符号、Shorの9量子ビット符号、スタビライザ)と、スタビライザ形式論とSteane符号(CSS構成、シンドローム復号、横断的Hadamard)です(#399)。
新しいControlled Gatesチュートリアルのために、チュートリアル04〜09を05〜10に振り直しました。例えば、以前のチュートリアル04(リソース推定)はチュートリアル05に、以前のチュートリアル09(コンパイルとトランスパイル)はチュートリアル10になりました。v0.12.4より前の特定のチュートリアルファイルパスへの外部リンクは更新が必要です。