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

Qamomile v0.12.6では、回路の逆操作を作るqmc.inverseを追加しました。ビルトインゲート、@qkernel全体、QFT/IQFTをそのまま逆操作に変換でき、得られた逆操作は元と同じように呼び出せます。また、計算基底のレジスタを2^nを法として±1シフトする算術プリミティブqmc.modular_increment / qmc.modular_decrementを追加しました。さらに、sample() / run()実行まわりのjob型・結果型はqamomile.circuitから直接importできるようになりました。不具合他王として、runtime parameterの式をゲート角度に使ったときのトランスパイル、bindingsで与えたVector要素の値解決、qmc.expvalが参照する量子ビットの対応付け、最適化converterのHUBOインスタンス対応もしています。

pip install qamomile==0.12.6

新機能

qmc.inverseによる回路の逆操作

qmc.inverse(target)は、ビルトインゲート関数、@qkernel、stdlibのQFT関数の逆操作を返します。固定ゲートは対応する随伴ゲートになり(qmc.inverse(qmc.s)qmc.sdgqmc.hqmc.cxのような自己逆ゲートはそれ自身)、回転ゲート(rxryrzpcprzz)は角度の符号が反転します。qmc.inverse(qmc.qft)qmc.iqftをそのまま返すため、composite gateをネイティブに出力できるSDKではその経路が維持されます。Vector[Qubit]へのbroadcastも順方向のゲートと同じように動きます(#445)。

@qkernelに対しては、元の量子カーネルと同じ引数で呼び出せるwrapperが返り、本体を逆順にしつつ各操作を逆にして適用します。入れ子の量子カーネル呼び出し、composite gate、qmc.control(...)の結果、qmc.pauli_evolve(発展時間の符号を反転)、qmc.rangeループ(unrollせずに反復順を逆転)も再帰的に逆変換されます。qmc.inverse(...)を呼ぶ量子カーネル自体を逆変換すると、入れ子のinverseは打ち消されて元の操作列に戻ります。

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

@qmc.qkernel
def layer(q: qmc.Qubit, angle: qmc.Float) -> qmc.Qubit:
    q = qmc.h(q)
    q = qmc.rz(q, angle)
    return q

@qmc.qkernel
def roundtrip(angle: qmc.Float) -> qmc.Bit:
    q = qmc.qubit("q")
    q = layer(q, angle)
    q = qmc.inverse(layer)(q, angle)  # uncomputeでqは|0>に戻る
    return qmc.measure(q)

executable = QiskitTranspiler().transpile(roundtrip, bindings={"angle": 0.37})

if / while / for ... in qmc.items(...)の制御フローを含む量子カーネルや、inverse wrapperのトレース時点でループ範囲がsymbolicなままの量子カーネルはサポートしておらず、NotImplementedErrorになります(bindingsで与えたループ範囲は問題なく解決されます)。内部で量子ビットを確保する量子カーネルも拒否されます。

modular incrementとmodular decrement

qmc.modular_incrementqmc.modular_decrementは、little-endianの量子ビットレジスタ(q[0]が最下位ビット)に|j> -> |j ± 1 mod 2^n>を適用します。構成はQFTを使わず、Xゲートとmulti-controlled Xゲートだけで組み立てられています。制御版は専用APIではなく、qmc.control(qmc.modular_increment, num_controls=1)のように既存の制御機構との組み合わせで作ります。どちらの量子カーネルもqamomile.circuit.algorithm.arithmeticからimportできます(#453)。

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

@qmc.qkernel
def plus_one(n: qmc.UInt) -> qmc.Vector[qmc.Bit]:
    q = qmc.qubit_array(n, name="q")
    q[1] = qmc.x(q[1])            # |j=2>を準備(little-endian)
    q = qmc.modular_increment(q)  # |j=2> -> |j=3>
    return qmc.measure(q)

executable = QiskitTranspiler().transpile(plus_one, bindings={"n": 3})

QURI Partsでのサポートは現状部分的で、通常のシフトは2量子ビット以下のレジスタ、制御版は1量子ビットのレジスタに限られます。

qamomile.circuit配下のjob型・結果型

SampleResultSampleJobRunJobExpvalJobJobJobStatusqamomile.circuitから再エクスポートしました。これらはsample() / run()実行まわりの型です。executable.sample()SampleJobを返し、その.result()SampleResultになります。executable.run()RunJobまたはExpvalJobを返し、Job / JobStatusは共通の基底クラスとステータスのenumです。qmc.SampleResultのような型注釈のために内部パスqamomile.circuit.transpiler.jobをimportする必要はなくなりました。内部パスも後方互換性のため引き続きimportできます(#407)。

import qamomile.circuit as qmc

def best_bitstring(result: qmc.SampleResult) -> tuple[int, ...]:
    """最も多くサンプルされた測定結果を返す。"""
    ((value, _count),) = result.most_common(1)
    return value

バグ修正

ドキュメント

さらに詳しく